forked from OSchip/llvm-project
[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
This commit is contained in:
parent
13d3048ced
commit
c564701fbd
|
@ -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)) {
|
||||
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;
|
||||
}
|
||||
|
||||
// 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);
|
||||
|
||||
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");
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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}}
|
||||
}
|
||||
|
Loading…
Reference in New Issue