From: Yaxun Liu Date: Wed, 8 Jun 2016 15:11:21 +0000 (+0000) Subject: [OpenCL] Fix __builtin_astype for vec3 types. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=de5698de405866349ba1db4be46093909b582841;p=clang [OpenCL] Fix __builtin_astype for vec3 types. __builtin_astype does not generate correct LLVM IR for vec3 types. This patch inserts bitcasts to/from vec4 when necessary in addition to generating vector shuffle. Sema and codegen tests are added. Differential Revision: http://reviews.llvm.org/D20133 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@272153 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/CodeGen/CGExprScalar.cpp b/lib/CodeGen/CGExprScalar.cpp index 0e49ce6aaf..67ee517d6a 100644 --- a/lib/CodeGen/CGExprScalar.cpp +++ b/lib/CodeGen/CGExprScalar.cpp @@ -3382,50 +3382,48 @@ Value *ScalarExprEmitter::VisitBlockExpr(const BlockExpr *block) { 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"); diff --git a/test/CodeGenOpenCL/as_type.cl b/test/CodeGenOpenCL/as_type.cl new file mode 100644 index 0000000000..f43692e760 --- /dev/null +++ b/test/CodeGenOpenCL/as_type.cl @@ -0,0 +1,68 @@ +// 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; +typedef __attribute__(( ext_vector_type(16) )) char char16; +typedef __attribute__(( ext_vector_type(3) )) int int3; + +//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-NOT: shufflevector +//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-NOT: shufflevector +//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-NOT: bitcast +//CHECK-NOT: shufflevector +//CHECK: ret <3 x i8> %[[x]] +char3 f7(char3 x) { + return __builtin_astype(x, char3); +} + +//CHECK: define spir_func <3 x i32> @f8(<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); +} diff --git a/test/SemaOpenCL/as_type.cl b/test/SemaOpenCL/as_type.cl new file mode 100644 index 0000000000..f0bf4d7dae --- /dev/null +++ b/test/SemaOpenCL/as_type.cl @@ -0,0 +1,13 @@ +// RUN: %clang_cc1 %s -emit-llvm -triple spir-unknown-unknown -o - -verify -fsyntax-only + +typedef __attribute__(( ext_vector_type(3) )) char char3; +typedef __attribute__(( ext_vector_type(16) )) char char16; + +char3 f1(char16 x) { + return __builtin_astype(x, char3); // expected-error{{invalid reinterpretation: sizes of 'char3' (vector of 3 'char' values) and 'char16' (vector of 16 'char' values) must match}} +} + +char16 f3(int x) { + return __builtin_astype(x, char16); // expected-error{{invalid reinterpretation: sizes of 'char16' (vector of 16 'char' values) and 'int' must match}} +} +