From 61eee0ca33b29e102f11bab77c8b74cc00e2392b Mon Sep 17 00:00:00 2001 From: Tanya Lattner Date: Sat, 4 Jun 2011 00:47:47 +0000 Subject: [PATCH] Add support for builtin astype: __builtin_astype(): Used to reinterpreted as another data type of the same size using for both scalar and vector data types. Added test case. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@132612 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/AST/Expr.h | 38 ++++++++++++++++ include/clang/AST/RecursiveASTVisitor.h | 3 ++ include/clang/Basic/DiagnosticSemaKinds.td | 4 ++ include/clang/Basic/StmtNodes.td | 2 + include/clang/Basic/TokenKinds.def | 1 + include/clang/Sema/Sema.h | 7 +++ include/clang/Serialization/ASTBitCodes.h | 5 ++- lib/AST/ExprClassification.cpp | 1 + lib/AST/ExprConstant.cpp | 1 + lib/AST/ItaniumMangle.cpp | 4 +- lib/AST/StmtPrinter.cpp | 7 +++ lib/AST/StmtProfile.cpp | 4 ++ lib/CodeGen/CGExprScalar.cpp | 51 ++++++++++++++++++++++ lib/Parse/ParseExpr.cpp | 30 +++++++++++++ lib/Sema/SemaExpr.cpp | 20 +++++++++ lib/Sema/TreeTransform.h | 7 +++ lib/Serialization/ASTReaderStmt.cpp | 6 ++- lib/Serialization/ASTWriterStmt.cpp | 11 +++++ lib/StaticAnalyzer/Core/ExprEngine.cpp | 1 + test/Parser/opencl-astype.cl | 20 +++++++++ tools/libclang/CXCursor.cpp | 1 + 21 files changed, 221 insertions(+), 3 deletions(-) create mode 100644 test/Parser/opencl-astype.cl diff --git a/include/clang/AST/Expr.h b/include/clang/AST/Expr.h index 9658cfdd5d..3212534e91 100644 --- a/include/clang/AST/Expr.h +++ b/include/clang/AST/Expr.h @@ -4026,6 +4026,44 @@ public: child_range children() { return child_range(); } }; +/// AsTypeExpr - Clang builtin function __builtin_astype [OpenCL 6.2.4.2] +/// This AST node provides support for reinterpreting a type to another +/// type of the same size. +class AsTypeExpr : public Expr { +private: + Expr* SrcExpr; + QualType DstType; + SourceLocation BuiltinLoc, RParenLoc; + +public: + AsTypeExpr(Expr* SrcExpr, QualType DstType, + ExprValueKind VK, ExprObjectKind OK, + SourceLocation BuiltinLoc, SourceLocation RParenLoc) + : Expr(AsTypeExprClass, DstType, VK, OK, false, false, false), + SrcExpr(SrcExpr), DstType(DstType), + BuiltinLoc(BuiltinLoc), RParenLoc(RParenLoc) {} + + /// \brief Build an empty __builtin_astype + explicit AsTypeExpr(EmptyShell Empty) : Expr(AsTypeExprClass, Empty) {} + + ~AsTypeExpr() { } + + /// getSrcExpr - Return the Expr to be converted. + Expr *getSrcExpr() const { return SrcExpr; } + QualType getDstType() const { return DstType; } + + virtual SourceRange getSourceRange() const { + return SourceRange(BuiltinLoc, RParenLoc); + } + + static bool classof(const Stmt *T) { + return T->getStmtClass() == AsTypeExprClass; + } + static bool classof(const AsTypeExpr *) { return true; } + + // Iterators + child_range children() { return child_range(); } +}; } // end namespace clang #endif diff --git a/include/clang/AST/RecursiveASTVisitor.h b/include/clang/AST/RecursiveASTVisitor.h index d97bb376a0..a8f182a5bc 100644 --- a/include/clang/AST/RecursiveASTVisitor.h +++ b/include/clang/AST/RecursiveASTVisitor.h @@ -1981,6 +1981,9 @@ DEF_TRAVERSE_STMT(FloatingLiteral, { }) DEF_TRAVERSE_STMT(ImaginaryLiteral, { }) DEF_TRAVERSE_STMT(StringLiteral, { }) DEF_TRAVERSE_STMT(ObjCStringLiteral, { }) + +// Traverse OpenCL: AsType, Convert. +DEF_TRAVERSE_STMT(AsTypeExpr, { }) // FIXME: look at the following tricky-seeming exprs to see if we // need to recurse on anything. These are ones that have methods diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index b6183cad35..83644b618e 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -4097,6 +4097,10 @@ def err_unknown_any_var_function_type : Error< def err_filter_expression_integral : Error< "filter expression type should be an integral value not %0">; +// OpenCL warnings and errors. +def err_invalid_astype_of_different_size : Error< + "invalid reinterpretation: sizes of %0 and %1 must match">; + } // end of sema category } // end of sema component. diff --git a/include/clang/Basic/StmtNodes.td b/include/clang/Basic/StmtNodes.td index 15ac760ce7..03f4cc3ec6 100644 --- a/include/clang/Basic/StmtNodes.td +++ b/include/clang/Basic/StmtNodes.td @@ -146,3 +146,5 @@ def SEHTryStmt : Stmt; def SEHExceptStmt : Stmt; def SEHFinallyStmt : Stmt; +// OpenCL Extensions. +def AsTypeExpr : DStmt; diff --git a/include/clang/Basic/TokenKinds.def b/include/clang/Basic/TokenKinds.def index 11865247af..dfba7eec8a 100644 --- a/include/clang/Basic/TokenKinds.def +++ b/include/clang/Basic/TokenKinds.def @@ -413,6 +413,7 @@ KEYWORD(__read_write , KEYOPENCL) ALIAS("read_only", __read_only , KEYOPENCL) ALIAS("write_only", __write_only , KEYOPENCL) ALIAS("read_write", __read_write , KEYOPENCL) +KEYWORD(__builtin_astype , KEYOPENCL) // Borland Extensions. KEYWORD(__pascal , KEYALL) diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index a3dd687e3a..0b32d5d905 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -2424,6 +2424,13 @@ public: ExprResult ActOnBlockStmtExpr(SourceLocation CaretLoc, Stmt *Body, Scope *CurScope); + //===---------------------------- OpenCL Features -----------------------===// + + /// __builtin_astype(...) + ExprResult ActOnAsTypeExpr(Expr *expr, ParsedType DestTy, + SourceLocation BuiltinLoc, + SourceLocation RParenLoc); + //===---------------------------- C++ Features --------------------------===// // Act on C++ namespaces diff --git a/include/clang/Serialization/ASTBitCodes.h b/include/clang/Serialization/ASTBitCodes.h index 96885075af..c881b23ed1 100644 --- a/include/clang/Serialization/ASTBitCodes.h +++ b/include/clang/Serialization/ASTBitCodes.h @@ -1003,7 +1003,10 @@ namespace clang { // CUDA - EXPR_CUDA_KERNEL_CALL // CUDAKernelCallExpr + EXPR_CUDA_KERNEL_CALL, // CUDAKernelCallExpr + + // OpenCL + EXPR_ASTYPE // An AsTypeExpr record. }; /// \brief The kinds of designators that can occur in a diff --git a/lib/AST/ExprClassification.cpp b/lib/AST/ExprClassification.cpp index 7e4d06ac30..d177cb5cbc 100644 --- a/lib/AST/ExprClassification.cpp +++ b/lib/AST/ExprClassification.cpp @@ -161,6 +161,7 @@ static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) { case Expr::InitListExprClass: case Expr::SizeOfPackExprClass: case Expr::SubstNonTypeTemplateParmPackExprClass: + case Expr::AsTypeExprClass: return Cl::CL_PRValue; // Next come the complicated cases. diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp index 1206fe7fb3..06c5645afb 100644 --- a/lib/AST/ExprConstant.cpp +++ b/lib/AST/ExprConstant.cpp @@ -2770,6 +2770,7 @@ static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) { case Expr::OpaqueValueExprClass: case Expr::PackExpansionExprClass: case Expr::SubstNonTypeTemplateParmPackExprClass: + case Expr::AsTypeExprClass: return ICEDiag(2, E->getLocStart()); case Expr::SizeOfPackExprClass: diff --git a/lib/AST/ItaniumMangle.cpp b/lib/AST/ItaniumMangle.cpp index aad6e9c48d..53c204562a 100644 --- a/lib/AST/ItaniumMangle.cpp +++ b/lib/AST/ItaniumMangle.cpp @@ -2093,7 +2093,9 @@ void CXXNameMangler::mangleExpression(const Expr *E, unsigned Arity) { case Expr::VAArgExprClass: case Expr::CXXUuidofExprClass: case Expr::CXXNoexceptExprClass: - case Expr::CUDAKernelCallExprClass: { + case Expr::CUDAKernelCallExprClass: + case Expr::AsTypeExprClass: + { // As bad as this diagnostic is, it's better than crashing. Diagnostic &Diags = Context.getDiags(); unsigned DiagID = Diags.getCustomDiagID(Diagnostic::Error, diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp index 1ef601c09b..87588e4518 100644 --- a/lib/AST/StmtPrinter.cpp +++ b/lib/AST/StmtPrinter.cpp @@ -1499,6 +1499,13 @@ void StmtPrinter::VisitBlockDeclRefExpr(BlockDeclRefExpr *Node) { void StmtPrinter::VisitOpaqueValueExpr(OpaqueValueExpr *Node) {} +void StmtPrinter::VisitAsTypeExpr(AsTypeExpr *Node) { + OS << "__builtin_astype("; + PrintExpr(Node->getSrcExpr()); + OS << ", " << Node->getType().getAsString(); + OS << ")"; +} + //===----------------------------------------------------------------------===// // Stmt method implementations //===----------------------------------------------------------------------===// diff --git a/lib/AST/StmtProfile.cpp b/lib/AST/StmtProfile.cpp index 44818e8c08..b117cd9a52 100644 --- a/lib/AST/StmtProfile.cpp +++ b/lib/AST/StmtProfile.cpp @@ -679,6 +679,10 @@ void StmtProfiler::VisitCUDAKernelCallExpr(CUDAKernelCallExpr *S) { VisitCallExpr(S); } +void StmtProfiler::VisitAsTypeExpr(AsTypeExpr *S) { + VisitExpr(S); +} + void StmtProfiler::VisitCXXNamedCastExpr(CXXNamedCastExpr *S) { VisitExplicitCastExpr(S); } diff --git a/lib/CodeGen/CGExprScalar.cpp b/lib/CodeGen/CGExprScalar.cpp index b1d457589d..dff7bf45e0 100644 --- a/lib/CodeGen/CGExprScalar.cpp +++ b/lib/CodeGen/CGExprScalar.cpp @@ -508,6 +508,7 @@ public: Value *VisitObjCStringLiteral(const ObjCStringLiteral *E) { return CGF.EmitObjCStringLiteral(E); } + Value *VisitAsTypeExpr(AsTypeExpr *CE); }; } // end anonymous namespace. @@ -2545,6 +2546,56 @@ Value *ScalarExprEmitter::VisitBlockExpr(const BlockExpr *block) { return CGF.EmitBlockLiteral(block); } +Value *ScalarExprEmitter::VisitAsTypeExpr(AsTypeExpr *E) { + Value *Src = CGF.EmitScalarExpr(E->getSrcExpr()); + const llvm::Type * DstTy = ConvertType(E->getDstType()); + + // Going from vec4->vec3 or vec3->vec4 is a special case and requires + // a shuffle vector instead of a bitcast. + const llvm::Type *SrcTy = Src->getType(); + if (isa(DstTy) && isa(SrcTy)) { + unsigned numElementsDst = cast(DstTy)->getNumElements(); + unsigned numElementsSrc = cast(SrcTy)->getNumElements(); + if ((numElementsDst == 3 && numElementsSrc == 4) + || (numElementsDst == 4 && numElementsSrc == 3)) { + + + // In the case of going from int4->float3, a bitcast is needed before + // doing a shuffle. + const llvm::Type *srcElemTy = + cast(SrcTy)->getElementType(); + const llvm::Type *dstElemTy = + cast(DstTy)->getElementType(); + + if ((srcElemTy->isIntegerTy() && dstElemTy->isFloatTy()) + || (srcElemTy->isFloatTy() && dstElemTy->isIntegerTy())) { + // Create a float type of the same size as the source or destination. + const llvm::VectorType *newSrcTy = llvm::VectorType::get(dstElemTy, + numElementsSrc); + + Src = Builder.CreateBitCast(Src, newSrcTy, "astypeCast"); + } + + llvm::Value *UnV = llvm::UndefValue::get(Src->getType()); + + llvm::SmallVector Args; + Args.push_back(Builder.getInt32(0)); + Args.push_back(Builder.getInt32(1)); + Args.push_back(Builder.getInt32(2)); + + if (numElementsDst == 4) + Args.push_back(llvm::UndefValue::get( + llvm::Type::getInt32Ty(CGF.getLLVMContext()))); + + llvm::Constant *Mask = llvm::ConstantVector::get(Args); + + return Builder.CreateShuffleVector(Src, UnV, Mask, "astype"); + } + } + + return Builder.CreateBitCast(Src, DstTy, "astype"); +} + //===----------------------------------------------------------------------===// // Entry Point into this File //===----------------------------------------------------------------------===// diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp index 25d505c2c5..89422b97fc 100644 --- a/lib/Parse/ParseExpr.cpp +++ b/lib/Parse/ParseExpr.cpp @@ -785,6 +785,7 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression, case tok::kw___builtin_va_arg: case tok::kw___builtin_offsetof: case tok::kw___builtin_choose_expr: + case tok::kw___builtin_astype: // primary-expression: [OCL] as_type() return ParseBuiltinPrimaryExpression(); case tok::kw___null: return Actions.ActOnGNUNullExpr(ConsumeToken()); @@ -1533,6 +1534,7 @@ ExprResult Parser::ParseUnaryExprOrTypeTraitExpression() { /// [GNU] '__builtin_choose_expr' '(' assign-expr ',' assign-expr ',' /// assign-expr ')' /// [GNU] '__builtin_types_compatible_p' '(' type-name ',' type-name ')' +/// [OCL] '__builtin_astype' '(' type-name expr ')' /// /// [GNU] offsetof-member-designator: /// [GNU] identifier @@ -1677,7 +1679,35 @@ ExprResult Parser::ParseBuiltinPrimaryExpression() { Expr2.take(), ConsumeParen()); break; } + case tok::kw___builtin_astype: { + // 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.ActOnAsTypeExpr(Expr.take(), DestTy.get(), StartLoc, + ConsumeParen()); + break; } +} if (Res.isInvalid()) return ExprError(); diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 1006b15ff1..1914a6a6ba 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -4995,6 +4995,26 @@ Sema::ActOnCUDAExecConfigExpr(Scope *S, SourceLocation LLLLoc, return ActOnCallExpr(S, ConfigDR, LLLLoc, execConfig, GGGLoc, 0); } +/// ActOnAsTypeExpr - create a new asType (bitcast) from the arguments. +/// +/// __builtin_astype( value, dst type ) +/// +ExprResult Sema::ActOnAsTypeExpr(Expr *expr, ParsedType destty, + SourceLocation BuiltinLoc, + SourceLocation RParenLoc) { + ExprValueKind VK = VK_RValue; + ExprObjectKind OK = OK_Ordinary; + QualType DstTy = GetTypeFromParser(destty); + QualType SrcTy = expr->getType(); + if (Context.getTypeSize(DstTy) != Context.getTypeSize(SrcTy)) + return ExprError(Diag(BuiltinLoc, + diag::err_invalid_astype_of_different_size) + << DstTy.getAsString().c_str() + << SrcTy.getAsString().c_str() + << expr->getSourceRange()); + return Owned(new (Context) AsTypeExpr(expr, DstTy, VK, OK, 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 9186767c03..06017e7cba 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -7877,6 +7877,13 @@ TreeTransform::TransformBlockDeclRefExpr(BlockDeclRefExpr *E) { ND, NameInfo, 0); } +template +ExprResult +TreeTransform::TransformAsTypeExpr(AsTypeExpr *E) { + assert(false && "Cannot transform asType expressions yet"); + return SemaRef.Owned(E); +} + //===----------------------------------------------------------------------===// // Type reconstruction //===----------------------------------------------------------------------===// diff --git a/lib/Serialization/ASTReaderStmt.cpp b/lib/Serialization/ASTReaderStmt.cpp index 918db7e367..f3f67a76c4 100644 --- a/lib/Serialization/ASTReaderStmt.cpp +++ b/lib/Serialization/ASTReaderStmt.cpp @@ -189,7 +189,7 @@ namespace clang { void VisitOpaqueValueExpr(OpaqueValueExpr *E); // CUDA Expressions - void VisitCUDAKernelCallExpr(CUDAKernelCallExpr *E); + void VisitCUDAKernelCallExpr(CUDAKernelCallExpr *E); }; } @@ -2000,6 +2000,10 @@ Stmt *ASTReader::ReadStmtFromStream(PerFileData &F) { case EXPR_CUDA_KERNEL_CALL: S = new (Context) CUDAKernelCallExpr(*Context, Empty); break; + + case EXPR_ASTYPE: + S = new (Context) AsTypeExpr(Empty); + break; } // We hit a STMT_STOP, so we're done with this expression. diff --git a/lib/Serialization/ASTWriterStmt.cpp b/lib/Serialization/ASTWriterStmt.cpp index a3970080fd..00e2404946 100644 --- a/lib/Serialization/ASTWriterStmt.cpp +++ b/lib/Serialization/ASTWriterStmt.cpp @@ -165,6 +165,8 @@ namespace clang { // CUDA Expressions void VisitCUDAKernelCallExpr(CUDAKernelCallExpr *E); + + void VisitAsTypeExpr(AsTypeExpr *E); }; } @@ -1432,6 +1434,15 @@ void ASTStmtWriter::VisitCUDAKernelCallExpr(CUDAKernelCallExpr *E) { Code = serialization::EXPR_CUDA_KERNEL_CALL; } +//===----------------------------------------------------------------------===// +// OpenCL Expressions and Statements. +//===----------------------------------------------------------------------===// +void ASTStmtWriter::VisitAsTypeExpr(AsTypeExpr *E) { + VisitExpr(E); + Writer.AddStmt(E->getSrcExpr()); + Code = serialization::EXPR_ASTYPE; +} + //===----------------------------------------------------------------------===// // ASTWriter Implementation //===----------------------------------------------------------------------===// diff --git a/lib/StaticAnalyzer/Core/ExprEngine.cpp b/lib/StaticAnalyzer/Core/ExprEngine.cpp index 6fd66c1f31..aed39eb0ce 100644 --- a/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ b/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -539,6 +539,7 @@ void ExprEngine::Visit(const Stmt* S, ExplodedNode* Pred, case Stmt::VAArgExprClass: case Stmt::CUDAKernelCallExprClass: case Stmt::OpaqueValueExprClass: + case Stmt::AsTypeExprClass: // Fall through. // Cases we intentionally don't evaluate, since they don't need diff --git a/test/Parser/opencl-astype.cl b/test/Parser/opencl-astype.cl new file mode 100644 index 0000000000..d476b841aa --- /dev/null +++ b/test/Parser/opencl-astype.cl @@ -0,0 +1,20 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s +#pragma OPENCL EXTENSION cl_khr_fp64 : enable + +void test_astype() { + float f = 1.0f; + unsigned int i = __builtin_astype(f, unsigned int); + + typedef __attribute__(( ext_vector_type(4) )) int int4; + typedef __attribute__(( ext_vector_type(3) )) float float3; + typedef __attribute__(( ext_vector_type(4) )) float float4; + typedef __attribute__(( ext_vector_type(4) )) double double4; + + float4 f4; + double4 d4 = __builtin_astype(f4, double4); // expected-error{{invalid reinterpretation: sizes of double4 and float4 must match}} + + // Verify int4->float3, float3->int4 works. + int4 i4; + float3 f3 = __builtin_astype(i4, float3); + i4 = __builtin_astype(f3, int4); +} \ No newline at end of file diff --git a/tools/libclang/CXCursor.cpp b/tools/libclang/CXCursor.cpp index 2a78012d89..b34370d2e6 100644 --- a/tools/libclang/CXCursor.cpp +++ b/tools/libclang/CXCursor.cpp @@ -173,6 +173,7 @@ CXCursor cxcursor::MakeCXCursor(Stmt *S, Decl *Parent, case Stmt::OpaqueValueExprClass: case Stmt::PackExpansionExprClass: case Stmt::SizeOfPackExprClass: + case Stmt::AsTypeExprClass: K = CXCursor_UnexposedExpr; break; -- 2.40.0