diff options
| author | Yaxun Liu <Yaxun.Liu@amd.com> | 2016-06-08 15:11:21 +0000 |
|---|---|---|
| committer | Yaxun Liu <Yaxun.Liu@amd.com> | 2016-06-08 15:11:21 +0000 |
| commit | c564701fbd62bbd47b001564ace2649c19ae92ce (patch) | |
| tree | 0f7f7cee8d011c821496fab2c5b7b9afa8ce0ff1 | |
| parent | 13d3048cedad51123d42fea730d30bcfaa7967fb (diff) | |
| download | bcm5719-llvm-c564701fbd62bbd47b001564ace2649c19ae92ce.tar.gz bcm5719-llvm-c564701fbd62bbd47b001564ace2649c19ae92ce.zip | |
[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
llvm-svn: 272153
| -rw-r--r-- | clang/lib/CodeGen/CGExprScalar.cpp | 74 | ||||
| -rw-r--r-- | clang/test/CodeGenOpenCL/as_type.cl | 68 | ||||
| -rw-r--r-- | clang/test/SemaOpenCL/as_type.cl | 13 |
3 files changed, 117 insertions, 38 deletions
diff --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp index 0e49ce6aaf3..67ee517d6ac 100644 --- a/clang/lib/CodeGen/CGExprScalar.cpp +++ b/clang/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<llvm::Constant*, 4> 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<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. - llvm::Type *srcElemTy = - cast<llvm::VectorType>(SrcTy)->getElementType(); - 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. - llvm::VectorType *newSrcTy = llvm::VectorType::get(dstElemTy, - numElementsSrc); - - Src = Builder.CreateBitCast(Src, newSrcTy, "astypeCast"); - } - - llvm::Value *UnV = llvm::UndefValue::get(Src->getType()); - - 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(CGF.Int32Ty)); - - llvm::Constant *Mask = llvm::ConstantVector::get(Args); + unsigned NumElementsSrc = isa<llvm::VectorType>(SrcTy) ? + cast<llvm::VectorType>(SrcTy)->getNumElements() : 0; + unsigned NumElementsDst = isa<llvm::VectorType>(DstTy) ? + cast<llvm::VectorType>(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/clang/test/CodeGenOpenCL/as_type.cl b/clang/test/CodeGenOpenCL/as_type.cl new file mode 100644 index 00000000000..f43692e7606 --- /dev/null +++ b/clang/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> <i32 0, i32 1, i32 2> +//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> <i32 0, i32 1, i32 2, i32 undef> +//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> <i32 0, i32 1, i32 2> +//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> <i32 0, i32 1, i32 2, i32 undef> +//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> <i32 0, i32 1, i32 2> +//CHECK: ret <3 x i32> %[[astype]] +int3 f8(char16 x) { + return __builtin_astype(x, int3); +} diff --git a/clang/test/SemaOpenCL/as_type.cl b/clang/test/SemaOpenCL/as_type.cl new file mode 100644 index 00000000000..f0bf4d7daef --- /dev/null +++ b/clang/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}} +} + |

