]> granicus.if.org Git - clang/commitdiff
Add support for builtin astype:
authorTanya Lattner <tonic@nondot.org>
Sat, 4 Jun 2011 00:47:47 +0000 (00:47 +0000)
committerTanya Lattner <tonic@nondot.org>
Sat, 4 Jun 2011 00:47:47 +0000 (00:47 +0000)
__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

21 files changed:
include/clang/AST/Expr.h
include/clang/AST/RecursiveASTVisitor.h
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/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/SemaExpr.cpp
lib/Sema/TreeTransform.h
lib/Serialization/ASTReaderStmt.cpp
lib/Serialization/ASTWriterStmt.cpp
lib/StaticAnalyzer/Core/ExprEngine.cpp
test/Parser/opencl-astype.cl [new file with mode: 0644]
tools/libclang/CXCursor.cpp

index 9658cfdd5d9dad0165ff2bd9249df681eb39c4a2..3212534e9131a7a7780880e2b63c94e28ea52336 100644 (file)
@@ -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
index d97bb376a03ccae3bccea9903cc1b14c3c4275a3..a8f182a5bc92afa8069e1b00c7218a43bfd0a722 100644 (file)
@@ -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
index b6183cad3575a795eee4683beeb440e04619ce58..83644b618ea69752efb527b39eab33945e71f615 100644 (file)
@@ -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.
index 15ac760ce7251b1d0987bcb5f2285fb8ab89dcf5..03f4cc3ec6d84c8691cda8ef208b264957cac549 100644 (file)
@@ -146,3 +146,5 @@ def SEHTryStmt : Stmt;
 def SEHExceptStmt : Stmt;
 def SEHFinallyStmt : Stmt;
 
+// OpenCL Extensions.
+def AsTypeExpr : DStmt<Expr>;
index 11865247af5f1cdad379a7e4667fe95a916c059d..dfba7eec8ae787d4144b9dcca8ac7fc6be98cd88 100644 (file)
@@ -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)
index a3dd687e3a123dc0c95f3e77311687dc5bffca82..0b32d5d9050afce53bcc459a67bd1480e4b43033 100644 (file)
@@ -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
index 96885075af0873145a3ce6496bba1b53a3ae1d23..c881b23ed116f3d4e1af91bd8554c90acc53d581 100644 (file)
@@ -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
index 7e4d06ac3070558cfb0e6c0740acd22b5ad9af55..d177cb5cbc97faf26fb40949e76633d70974e6a0 100644 (file)
@@ -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.
index 1206fe7fb33d2e67473da0f212347083c65b55e0..06c5645afb3f64ba678198470cc25ac2e223bbc6 100644 (file)
@@ -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:
index aad6e9c48dea5e3151c7158e211bc2ca1174b4a8..53c204562a0ff66e19b5f6067ca74a50ac4e1b1e 100644 (file)
@@ -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,
index 1ef601c09be47726fac71e0859e7c05dc742e10a..87588e4518842ac6f977f963445456f082fabab1 100644 (file)
@@ -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
 //===----------------------------------------------------------------------===//
index 44818e8c0847cc29cb1db3a201be57e9c438d049..b117cd9a525face025636224eb709f5aa1ca7a44 100644 (file)
@@ -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);
 }
index b1d457589d82c7d7f794aa99fbfedb50d1a9ce13..dff7bf45e0c3b89f8a47f2f8a8a7522ab29b1849 100644 (file)
@@ -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<llvm::VectorType>(DstTy) && isa<llvm::VectorType>(SrcTy)) {
+    unsigned numElementsDst = cast<llvm::VectorType>(DstTy)->getNumElements();
+    unsigned numElementsSrc = cast<llvm::VectorType>(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<llvm::VectorType>(SrcTy)->getElementType();
+      const llvm::Type *dstElemTy = 
+      cast<llvm::VectorType>(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<llvm::Constant*, 3> 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
 //===----------------------------------------------------------------------===//
index 25d505c2c595768218d8bb503d4a0f109b5f3cb1..89422b97fc1fcc008a2b54ae28d27ab5cfdf7b96 100644 (file)
@@ -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();
index 1006b15ff1d04b0a94a1552253639a0692e0cd8c..1914a6a6ba777a125a1f75269b2760615ae6258d 100644 (file)
@@ -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
index 9186767c038c1f1c73c000a166204c8099e664ae..06017e7cbabd90b3b525a174f78d2a9e4ade5a63 100644 (file)
@@ -7877,6 +7877,13 @@ TreeTransform<Derived>::TransformBlockDeclRefExpr(BlockDeclRefExpr *E) {
                                          ND, NameInfo, 0);
 }
 
+template<typename Derived>
+ExprResult
+TreeTransform<Derived>::TransformAsTypeExpr(AsTypeExpr *E) {
+  assert(false && "Cannot transform asType expressions yet");
+  return SemaRef.Owned(E);
+}
+  
 //===----------------------------------------------------------------------===//
 // Type reconstruction
 //===----------------------------------------------------------------------===//
index 918db7e367c675e3945463ca50455829b8f2e2fc..f3f67a76c4d4258022db9b320d72120d8ec2207e 100644 (file)
@@ -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.
index a3970080fd0b9faef0e17ea291400a58b4f17f55..00e240494645dc67f581e8308d320a2b94653216 100644 (file)
@@ -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
 //===----------------------------------------------------------------------===//
index 6fd66c1f310c5f655bb9e563bf1bfb446af86960..aed39eb0cec6b7f77f3bfbd146415d681fc3f4a6 100644 (file)
@@ -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 (file)
index 0000000..d476b84
--- /dev/null
@@ -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
index 2a78012d8917736c6ac05666032fdd5b5f2499c4..b34370d2e6527b9bc8b5768447ea025f2ac5b7f3 100644 (file)
@@ -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;