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
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
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.
def SEHExceptStmt : Stmt;
def SEHFinallyStmt : Stmt;
+// OpenCL Extensions.
+def AsTypeExpr : DStmt<Expr>;
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)
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
// 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
case Expr::InitListExprClass:
case Expr::SizeOfPackExprClass:
case Expr::SubstNonTypeTemplateParmPackExprClass:
+ case Expr::AsTypeExprClass:
return Cl::CL_PRValue;
// Next come the complicated cases.
case Expr::OpaqueValueExprClass:
case Expr::PackExpansionExprClass:
case Expr::SubstNonTypeTemplateParmPackExprClass:
+ case Expr::AsTypeExprClass:
return ICEDiag(2, E->getLocStart());
case Expr::SizeOfPackExprClass:
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,
void StmtPrinter::VisitOpaqueValueExpr(OpaqueValueExpr *Node) {}
+void StmtPrinter::VisitAsTypeExpr(AsTypeExpr *Node) {
+ OS << "__builtin_astype(";
+ PrintExpr(Node->getSrcExpr());
+ OS << ", " << Node->getType().getAsString();
+ OS << ")";
+}
+
//===----------------------------------------------------------------------===//
// Stmt method implementations
//===----------------------------------------------------------------------===//
VisitCallExpr(S);
}
+void StmtProfiler::VisitAsTypeExpr(AsTypeExpr *S) {
+ VisitExpr(S);
+}
+
void StmtProfiler::VisitCXXNamedCastExpr(CXXNamedCastExpr *S) {
VisitExplicitCastExpr(S);
}
Value *VisitObjCStringLiteral(const ObjCStringLiteral *E) {
return CGF.EmitObjCStringLiteral(E);
}
+ Value *VisitAsTypeExpr(AsTypeExpr *CE);
};
} // end anonymous namespace.
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
//===----------------------------------------------------------------------===//
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());
/// [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
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();
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
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
//===----------------------------------------------------------------------===//
void VisitOpaqueValueExpr(OpaqueValueExpr *E);
// CUDA Expressions
- void VisitCUDAKernelCallExpr(CUDAKernelCallExpr *E);
+ void VisitCUDAKernelCallExpr(CUDAKernelCallExpr *E);
};
}
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.
// CUDA Expressions
void VisitCUDAKernelCallExpr(CUDAKernelCallExpr *E);
+
+ void VisitAsTypeExpr(AsTypeExpr *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
//===----------------------------------------------------------------------===//
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
--- /dev/null
+// 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
case Stmt::OpaqueValueExprClass:
case Stmt::PackExpansionExprClass:
case Stmt::SizeOfPackExprClass:
+ case Stmt::AsTypeExprClass:
K = CXCursor_UnexposedExpr;
break;