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
diff --git a/lib/AST/ExprClassification.cpp b/lib/AST/ExprClassification.cpp
index 7e4d06a..d177cb5 100644
--- a/lib/AST/ExprClassification.cpp
+++ b/lib/AST/ExprClassification.cpp
@@ -161,6 +161,7 @@
   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 1206fe7..06c5645 100644
--- a/lib/AST/ExprConstant.cpp
+++ b/lib/AST/ExprConstant.cpp
@@ -2770,6 +2770,7 @@
   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 aad6e9c..53c2045 100644
--- a/lib/AST/ItaniumMangle.cpp
+++ b/lib/AST/ItaniumMangle.cpp
@@ -2093,7 +2093,9 @@
   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 1ef601c..87588e4 100644
--- a/lib/AST/StmtPrinter.cpp
+++ b/lib/AST/StmtPrinter.cpp
@@ -1499,6 +1499,13 @@
 
 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 44818e8..b117cd9 100644
--- a/lib/AST/StmtProfile.cpp
+++ b/lib/AST/StmtProfile.cpp
@@ -679,6 +679,10 @@
   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 b1d4575..dff7bf4 100644
--- a/lib/CodeGen/CGExprScalar.cpp
+++ b/lib/CodeGen/CGExprScalar.cpp
@@ -508,6 +508,7 @@
   Value *VisitObjCStringLiteral(const ObjCStringLiteral *E) {
     return CGF.EmitObjCStringLiteral(E);
   }
+  Value *VisitAsTypeExpr(AsTypeExpr *CE);
 };
 }  // end anonymous namespace.
 
@@ -2545,6 +2546,56 @@
   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
 //===----------------------------------------------------------------------===//
diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp
index 25d505c..89422b9 100644
--- a/lib/Parse/ParseExpr.cpp
+++ b/lib/Parse/ParseExpr.cpp
@@ -785,6 +785,7 @@
   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 @@
 /// [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 @@
                                   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 1006b15..1914a6a 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -4995,6 +4995,26 @@
   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 9186767..06017e7 100644
--- a/lib/Sema/TreeTransform.h
+++ b/lib/Sema/TreeTransform.h
@@ -7877,6 +7877,13 @@
                                          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
 //===----------------------------------------------------------------------===//
diff --git a/lib/Serialization/ASTReaderStmt.cpp b/lib/Serialization/ASTReaderStmt.cpp
index 918db7e..f3f67a7 100644
--- a/lib/Serialization/ASTReaderStmt.cpp
+++ b/lib/Serialization/ASTReaderStmt.cpp
@@ -189,7 +189,7 @@
     void VisitOpaqueValueExpr(OpaqueValueExpr *E);
     
     // CUDA Expressions
-    void VisitCUDAKernelCallExpr(CUDAKernelCallExpr *E);
+    void VisitCUDAKernelCallExpr(CUDAKernelCallExpr *E);    
   };
 }
 
@@ -2000,6 +2000,10 @@
     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 a397008..00e2404 100644
--- a/lib/Serialization/ASTWriterStmt.cpp
+++ b/lib/Serialization/ASTWriterStmt.cpp
@@ -165,6 +165,8 @@
 
     // CUDA Expressions
     void VisitCUDAKernelCallExpr(CUDAKernelCallExpr *E);
+    
+    void VisitAsTypeExpr(AsTypeExpr *E);
   };
 }
 
@@ -1433,6 +1435,15 @@
 }
 
 //===----------------------------------------------------------------------===//
+// 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 6fd66c1..aed39eb 100644
--- a/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ b/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -539,6 +539,7 @@
     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