Index: include/clang/Basic/DiagnosticKinds.def =================================================================== --- include/clang/Basic/DiagnosticKinds.def (revision 51087) +++ include/clang/Basic/DiagnosticKinds.def (working copy) @@ -1056,4 +1056,13 @@ DIAG(ext_return_has_expr, EXTENSION, "void function '%0' should not return a value") +DIAG(err_shufflevector_non_vector, ERROR, + "first two arguments to __builtin_shufflevector must be vectors") +DIAG(err_shufflevector_incompatible_vector, ERROR, + "first two arguments to __builtin_shufflevector must have the same type") +DIAG(err_shufflevector_nonconstant_argument, ERROR, + "indexes for __builtin_shufflevector must be constant integers") +DIAG(err_shufflevector_argument_too_large, ERROR, + "indexes for __builtin_shufflevector must be less than the total number of vector elements") + #undef DIAG Index: include/clang/AST/Builtins.def =================================================================== --- include/clang/AST/Builtins.def (revision 51087) +++ include/clang/AST/Builtins.def (working copy) @@ -96,6 +96,8 @@ BUILTIN(__builtin_memcpy, "v*v*vC*z", "n") BUILTIN(__builtin_expect, "iii" , "nc") +BUILTIN(__builtin_shufflevector, "v." , "nc") + BUILTIN(__builtin_alloca, "v*z" , "n") // Atomic operators builtin. Index: include/clang/AST/Expr.h =================================================================== --- include/clang/AST/Expr.h (revision 51087) +++ include/clang/AST/Expr.h (working copy) @@ -1095,6 +1095,75 @@ virtual child_iterator child_end(); }; +/// ShuffleVectorExpr - clang-specific builtin-in function +/// __builtin_shufflevector. +/// This AST node represents a operator that does a constant +/// shuffle, similar to LLVM's shufflevector instruction. It takes +/// two vectors and a variable number of constant indices, +/// and returns the appropriately shuffled vector. +class ShuffleVectorExpr : public Expr { + SourceLocation BuiltinLoc, RParenLoc; + + // SubExprs - the list of values passed to the __builtin_shufflevector + // function. The first two are vectors, and the rest are constant + // indices. The number of values in this list is always + // 2+the number of indices in the vector type. + Expr **SubExprs; + unsigned NumExprs; + +public: + ShuffleVectorExpr(Expr **args, unsigned nexpr, + QualType Type, SourceLocation BLoc, + SourceLocation RP) : + Expr(ShuffleVectorExprClass, Type), BuiltinLoc(BLoc), + RParenLoc(RP), NumExprs(nexpr) + { + SubExprs = new Expr*[nexpr]; + for (unsigned i = 0; i < nexpr; i++) + SubExprs[i] = args[i]; + } + + virtual SourceRange getSourceRange() const { + return SourceRange(BuiltinLoc, RParenLoc); + } + static bool classof(const Stmt *T) { + return T->getStmtClass() == ShuffleVectorExprClass; + } + static bool classof(const ShuffleVectorExpr *) { return true; } + + ~ShuffleVectorExpr() { + for (unsigned i = 0; i < NumExprs; i++) + delete SubExprs[i]; + delete [] SubExprs; + } + + /// getNumSubExprs - Return the size of the SubExprs array. This includes the + /// constant expression, the actual arguments passed in, and the function + /// pointers. + unsigned getNumSubExprs() const { return NumExprs; } + + /// getExpr - Return the Expr at the specified index. + Expr *getExpr(unsigned Index) { + assert((Index < NumExprs) && "Arg access out of range!"); + return SubExprs[Index]; + } + const Expr *getExpr(unsigned Index) const { + assert((Index < NumExprs) && "Arg access out of range!"); + return SubExprs[Index]; + } + + int getShuffleMaskIdx(ASTContext &Ctx, unsigned N) { + llvm::APSInt Result(32); + bool result = getExpr(N+2)->isIntegerConstantExpr(Result, Ctx); + assert(result && "Must be integer constant"); + return Result.getZExtValue(); + } + + // Iterators + virtual child_iterator child_begin(); + virtual child_iterator child_end(); +}; + /// ChooseExpr - GNU builtin-in function __builtin_choose_expr. /// This AST node is similar to the conditional operator (?:) in C, with /// the following exceptions: Index: include/clang/AST/StmtNodes.def =================================================================== --- include/clang/AST/StmtNodes.def (revision 51087) +++ include/clang/AST/StmtNodes.def (working copy) @@ -103,8 +103,9 @@ // Clang Extensions. STMT(76, OverloadExpr , Expr) +STMT(77, ShuffleVectorExpr , Expr) -LAST_EXPR(76) +LAST_EXPR(77) #undef STMT #undef FIRST_STMT Index: lib/CodeGen/CGExprScalar.cpp =================================================================== --- lib/CodeGen/CGExprScalar.cpp (revision 51087) +++ lib/CodeGen/CGExprScalar.cpp (working copy) @@ -127,6 +127,7 @@ Value *VisitObjCMessageExpr(ObjCMessageExpr *E); Value *VisitObjCIvarRefExpr(ObjCIvarRefExpr *E) { return EmitLoadOfLValue(E);} Value *VisitArraySubscriptExpr(ArraySubscriptExpr *E); + Value *VisitShuffleVectorExpr(ShuffleVectorExpr *E); Value *VisitMemberExpr(Expr *E) { return EmitLoadOfLValue(E); } Value *VisitExtVectorElementExpr(Expr *E) { return EmitLoadOfLValue(E); } Value *VisitCompoundLiteralExpr(CompoundLiteralExpr *E) { return EmitLoadOfLValue(E); } @@ -449,6 +450,17 @@ return llvm::UndefValue::get(CGF.ConvertType(E->getType())); } +Value *ScalarExprEmitter::VisitShuffleVectorExpr(ShuffleVectorExpr *E) { + std::vector indices; + for (unsigned i = 2; i < E->getNumSubExprs(); i++) { + indices.push_back(cast(CGF.EmitScalarExpr(E->getExpr(i)))); + } + Value* V1 = CGF.EmitScalarExpr(E->getExpr(0)); + Value* V2 = CGF.EmitScalarExpr(E->getExpr(1)); + Value* SV = llvm::ConstantVector::get(indices); + return Builder.CreateShuffleVector(V1, V2, SV, "shuffle"); +} + Value *ScalarExprEmitter::VisitObjCMessageExpr(ObjCMessageExpr *E) { // Only the lookup mechanism and first two arguments of the method // implementation vary between runtimes. We can get the receiver and Index: lib/Sema/SemaChecking.cpp =================================================================== --- lib/Sema/SemaChecking.cpp (revision 51087) +++ lib/Sema/SemaChecking.cpp (working copy) @@ -30,7 +30,7 @@ /// CheckFunctionCall - Check a direct function call for various correctness /// and safety properties not strictly enforced by the C type system. -bool +Action::ExprResult Sema::CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall) { // Get the IdentifierInfo* for the called function. @@ -40,23 +40,36 @@ case Builtin::BI__builtin___CFStringMakeConstantString: assert(TheCall->getNumArgs() == 1 && "Wrong # arguments to builtin CFStringMakeConstantString"); - return CheckBuiltinCFStringArgument(TheCall->getArg(0)); + if (!CheckBuiltinCFStringArgument(TheCall->getArg(0))) { + delete TheCall; + return true; + } + return TheCall; case Builtin::BI__builtin_va_start: - return SemaBuiltinVAStart(TheCall); - + if (!SemaBuiltinVAStart(TheCall)) { + delete TheCall; + return true; + } + return TheCall; case Builtin::BI__builtin_isgreater: case Builtin::BI__builtin_isgreaterequal: case Builtin::BI__builtin_isless: case Builtin::BI__builtin_islessequal: case Builtin::BI__builtin_islessgreater: case Builtin::BI__builtin_isunordered: - return SemaBuiltinUnorderedCompare(TheCall); + if (!SemaBuiltinUnorderedCompare(TheCall)) { + delete TheCall; + return true; + } + return TheCall; + case Builtin::BI__builtin_shufflevector: + return SemaBuiltinShuffleVector(TheCall); } // Search the KnownFunctionIDs for the identifier. unsigned i = 0, e = id_num_known_functions; for (; i != e; ++i) { if (KnownFunctionIDs[i] == FnInfo) break; } - if (i == e) return false; + if (i == e) return TheCall; // Printf checking. if (i <= id_vprintf) { @@ -82,7 +95,7 @@ CheckPrintfArguments(TheCall, HasVAListArg, format_idx); } - return false; + return TheCall; } /// CheckBuiltinCFStringArgument - Checks that the argument to the builtin @@ -200,7 +213,80 @@ return false; } +/// SemaBuiltinShuffleVector - Handle __builtin_shufflevector. +// This is declared to take (...), so we have to check everything. +Action::ExprResult Sema::SemaBuiltinShuffleVector(CallExpr *TheCall) { + if (TheCall->getNumArgs() < 3) + return Diag(TheCall->getLocEnd(), diag::err_typecheck_call_too_few_args, + TheCall->getSourceRange()); + QualType FAType = TheCall->getArg(0)->getType(); + QualType SAType = TheCall->getArg(1)->getType(); + + if (!FAType->isVectorType() || !SAType->isVectorType()) { + Diag(TheCall->getLocStart(), diag::err_shufflevector_non_vector, + SourceRange(TheCall->getArg(0)->getLocStart(), + TheCall->getArg(1)->getLocEnd())); + delete TheCall; + return true; + } + + if (TheCall->getArg(0)->getType().getCanonicalType().getUnqualifiedType() != + TheCall->getArg(1)->getType().getCanonicalType().getUnqualifiedType()) { + Diag(TheCall->getLocStart(), diag::err_shufflevector_incompatible_vector, + SourceRange(TheCall->getArg(0)->getLocStart(), + TheCall->getArg(1)->getLocEnd())); + delete TheCall; + return true; + } + + unsigned numElements = FAType->getAsVectorType()->getNumElements(); + if (TheCall->getNumArgs() != numElements+2) { + if (TheCall->getNumArgs() < numElements+2) + Diag(TheCall->getLocEnd(), diag::err_typecheck_call_too_few_args, + TheCall->getSourceRange()); + else + Diag(TheCall->getLocEnd(), diag::err_typecheck_call_too_many_args, + TheCall->getSourceRange()); + delete TheCall; + return true; + } + + for (unsigned i = 2; i < TheCall->getNumArgs(); i++) { + llvm::APSInt Result(32); + if (!TheCall->getArg(i)->isIntegerConstantExpr(Result, Context)) { + Diag(TheCall->getLocStart(), + diag::err_shufflevector_nonconstant_argument, + TheCall->getArg(i)->getSourceRange()); + delete TheCall; + return true; + } + if (Result.getActiveBits() > 64 || Result.getZExtValue() >= numElements*2) { + Diag(TheCall->getLocStart(), + diag::err_shufflevector_argument_too_large, + TheCall->getArg(i)->getSourceRange()); + delete TheCall; + return true; + } + } + + llvm::SmallVector exprs; + + for (unsigned i = 0; i < TheCall->getNumArgs(); i++) { + exprs.push_back(TheCall->getArg(i)); + TheCall->setArg(i, 0); + } + + ShuffleVectorExpr* E = new ShuffleVectorExpr( + exprs.begin(), numElements+2, FAType, + TheCall->getCallee()->getLocStart(), + TheCall->getRParenLoc()); + + delete TheCall; + + return E; +} + /// CheckPrintfArguments - Check calls to printf (and similar functions) for /// correct use of format strings. /// Index: lib/Sema/SemaExpr.cpp =================================================================== --- lib/Sema/SemaExpr.cpp (revision 51087) +++ lib/Sema/SemaExpr.cpp (working copy) @@ -723,8 +723,8 @@ } // Do special checking on direct calls to functions. - if (FDecl && CheckFunctionCall(FDecl, TheCall.get())) - return true; + if (FDecl) + return CheckFunctionCall(FDecl, TheCall.take()); return TheCall.take(); } Index: lib/Sema/Sema.h =================================================================== --- lib/Sema/Sema.h (revision 51087) +++ lib/Sema/Sema.h (working copy) @@ -887,10 +887,11 @@ //===--------------------------------------------------------------------===// // Extra semantic analysis beyond the C type system private: - bool CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall); + Action::ExprResult CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall); bool CheckBuiltinCFStringArgument(Expr* Arg); bool SemaBuiltinVAStart(CallExpr *TheCall); bool SemaBuiltinUnorderedCompare(CallExpr *TheCall); + Action::ExprResult SemaBuiltinShuffleVector(CallExpr *TheCall); void CheckPrintfArguments(CallExpr *TheCall, bool HasVAListArg, unsigned format_idx); void CheckReturnStackAddr(Expr *RetValExp, QualType lhsType, Index: lib/AST/Expr.cpp =================================================================== --- lib/AST/Expr.cpp (revision 51087) +++ lib/AST/Expr.cpp (working copy) @@ -1363,6 +1363,14 @@ return reinterpret_cast(&SubExprs[NumExprs]); } +// ShuffleVectorExpr +Stmt::child_iterator ShuffleVectorExpr::child_begin() { + return reinterpret_cast(&SubExprs[0]); +} +Stmt::child_iterator ShuffleVectorExpr::child_end() { + return reinterpret_cast(&SubExprs[NumExprs]); +} + // VAArgExpr Stmt::child_iterator VAArgExpr::child_begin() { return reinterpret_cast(&Val); Index: lib/AST/StmtPrinter.cpp =================================================================== --- lib/AST/StmtPrinter.cpp (revision 51087) +++ lib/AST/StmtPrinter.cpp (working copy) @@ -755,6 +755,15 @@ OS << ")"; } +void StmtPrinter::VisitShuffleVectorExpr(ShuffleVectorExpr *Node) { + OS << "__builtin_shufflevector("; + for (unsigned i = 0, e = Node->getNumSubExprs(); i != e; ++i) { + if (i) OS << ", "; + PrintExpr(Node->getExpr(i)); + } + OS << ")"; +} + void StmtPrinter::VisitInitListExpr(InitListExpr* Node) { OS << "{ "; for (unsigned i = 0, e = Node->getNumInits(); i != e; ++i) {