Index: lib/CodeGen/CGExprScalar.cpp =================================================================== --- lib/CodeGen/CGExprScalar.cpp +++ lib/CodeGen/CGExprScalar.cpp @@ -3398,50 +3398,48 @@ return CGF.EmitBlockLiteral(block); } +// Convert a vec3 to vec4, or vice versa. +static Value *ConvertVec3AndVec4(CGBuilderTy &Builder, CodeGenFunction &CGF, + Value *Src, unsigned numElementsDst) { + llvm::Value *UnV = llvm::UndefValue::get(Src->getType()); + 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(CGF.Int32Ty)); + llvm::Constant *Mask = llvm::ConstantVector::get(Args); + return Builder.CreateShuffleVector(Src, UnV, Mask); +} + Value *ScalarExprEmitter::VisitAsTypeExpr(AsTypeExpr *E) { Value *Src = CGF.EmitScalarExpr(E->getSrcExpr()); llvm::Type *DstTy = ConvertType(E->getType()); - // Going from vec4->vec3 or vec3->vec4 is a special case and requires - // a shuffle vector instead of a bitcast. 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. - llvm::Type *srcElemTy = - cast(SrcTy)->getElementType(); - 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. - llvm::VectorType *newSrcTy = llvm::VectorType::get(dstElemTy, - numElementsSrc); - - Src = Builder.CreateBitCast(Src, newSrcTy, "astypeCast"); - } - - llvm::Value *UnV = llvm::UndefValue::get(Src->getType()); - - 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(CGF.Int32Ty)); - - llvm::Constant *Mask = llvm::ConstantVector::get(Args); + unsigned numElementsSrc = isa(SrcTy) ? + cast(SrcTy)->getNumElements() : 0; + unsigned numElementsDst = isa(DstTy) ? + cast(DstTy)->getNumElements() : 0; + + // Going from vec3 to non-vec3 is a special case and requires a shuffle + // vector to get a vec4, then a bitcast if the target type is different. + if (numElementsSrc == 3 && numElementsDst != 3) { + Src = ConvertVec3AndVec4(Builder, CGF, Src, 4); + Src = Builder.CreateBitCast(Src, DstTy); + Src->setName("astype"); + return Src; + } - return Builder.CreateShuffleVector(Src, UnV, Mask, "astype"); - } + // Going from non-vec3 to vec3 is a special case and requires a bitcast + // to vec4 if the original type is not vec4, then a shuffle vector to + // get a vec3. + if (numElementsSrc != 3 && numElementsDst == 3) { + auto Vec4Ty = llvm::VectorType::get(DstTy->getVectorElementType(), 4); + Src = Builder.CreateBitCast(Src, Vec4Ty); + Src = ConvertVec3AndVec4(Builder, CGF, Src, 3); + Src->setName("astype"); + return Src; } return Builder.CreateBitCast(Src, DstTy, "astype"); Index: test/CodeGenOpenCL/as_type.cl =================================================================== --- /dev/null +++ test/CodeGenOpenCL/as_type.cl @@ -0,0 +1,63 @@ +// RUN: %clang_cc1 %s -emit-llvm -triple spir-unknown-unknown -o - | FileCheck %s + +typedef __attribute__(( ext_vector_type(3) )) char char3; +typedef __attribute__(( ext_vector_type(4) )) char char4; + +//CHECK: define spir_func <3 x i8> @f1(<4 x i8> %[[x:.*]]) +//CHECK: %[[astype:.*]] = shufflevector <4 x i8> %[[x]], <4 x i8> undef, <3 x i32> +//CHECK: ret <3 x i8> %[[astype]] +char3 f1(char4 x) { + return __builtin_astype(x, char3); +} + +//CHECK: define spir_func <4 x i8> @f2(<3 x i8> %[[x:.*]]) +//CHECK: %[[astype:.*]] = shufflevector <3 x i8> %[[x]], <3 x i8> undef, <4 x i32> +//CHECK: ret <4 x i8> %[[astype]] +char4 f2(char3 x) { + return __builtin_astype(x, char4); +} + +//CHECK: define spir_func <3 x i8> @f3(i32 %[[x:.*]]) +//CHECK: %[[cast:.*]] = bitcast i32 %[[x]] to <4 x i8> +//CHECK: %[[astype:.*]] = shufflevector <4 x i8> %[[cast]], <4 x i8> undef, <3 x i32> +//CHECK: ret <3 x i8> %[[astype]] +char3 f3(int x) { + return __builtin_astype(x, char3); +} + +//CHECK: define spir_func <4 x i8> @f4(i32 %[[x:.*]]) +//CHECK: %[[astype:.*]] = bitcast i32 %[[x]] to <4 x i8> +//CHECK: ret <4 x i8> %[[astype]] +char4 f4(int x) { + return __builtin_astype(x, char4); +} + +//CHECK: define spir_func i32 @f5(<3 x i8> %[[x:.*]]) +//CHECK: %[[shuffle:.*]] = shufflevector <3 x i8> %[[x]], <3 x i8> undef, <4 x i32> +//CHECK: %[[astype:.*]] = bitcast <4 x i8> %[[shuffle]] to i32 +//CHECK: ret i32 %[[astype]] +int f5(char3 x) { + return __builtin_astype(x, int); +} + +//CHECK: define spir_func i32 @f6(<4 x i8> %[[x:.*]]) +//CHECK: %[[astype]] = bitcast <4 x i8> %[[x]] to i32 +//CHECK: ret i32 %[[astype]] +int f6(char4 x) { + return __builtin_astype(x, int); +} + +//CHECK: define spir_func <3 x i8> @f7(<3 x i8> %[[x:.*]]) +//CHECK: ret <3 x i8> %[[x]] +char3 f7(char3 x) { + return __builtin_astype(x, char3); +} + +//CHECK: define spir_func <3 x i32> @f3(<16 x i8> %[[x:.*]]) +//CHECK: %[[cast:.*]] = bitcast <16 x i8> %[[x]] to <4 x i32> +//CHECK: %[[astype:.*]] = shufflevector <4 x i32> %[[cast]], <4 x i32> undef, <3 x i32> +//CHECK: ret <3 x i32> %[[astype]] +int3 f8(char16 x) { + return __builtin_astype(x, int3); +} +}