jtony created this revision. The vec_xxpermdi builtin is missing from altivec.h. This has been requested by developers working on libvpx for VP9 support for Google. Initially, I tried to define a new intrinsic to map it to the corresponding PowerPC hard instruction (XXPERMDI) directly. But there was feedback from the community that this can be done without introducing new intrinsic. This patch re-implement the vec_xxpermdi builtin by using the existing shuffleVector instruction just in the FE.
https://reviews.llvm.org/D33053 Files: include/clang/Basic/BuiltinsPPC.def include/clang/Basic/DiagnosticSemaKinds.td include/clang/Sema/Sema.h lib/CodeGen/CGBuiltin.cpp lib/Headers/altivec.h lib/Sema/SemaChecking.cpp test/CodeGen/builtins-ppc-error.c test/CodeGen/builtins-ppc-vsx.c
Index: test/CodeGen/builtins-ppc-vsx.c =================================================================== --- test/CodeGen/builtins-ppc-vsx.c +++ test/CodeGen/builtins-ppc-vsx.c @@ -1691,4 +1691,44 @@ res_vd = vec_neg(vd); // CHECK: fsub <2 x double> <double -0.000000e+00, double -0.000000e+00>, {{%[0-9]+}} // CHECK-LE: fsub <2 x double> <double -0.000000e+00, double -0.000000e+00>, {{%[0-9]+}} + +res_vd = vec_xxpermdi(vd, vd, 0); +// CHECK: shufflevector <2 x i64> %{{[0-9]+}}, <2 x i64> %{{[0-9]+}}, <2 x i32> <i32 0, i32 2> +// CHECK-LE: shufflevector <2 x i64> %{{[0-9]+}}, <2 x i64> %{{[0-9]+}}, <2 x i32> <i32 3, i32 1> + +res_vf = vec_xxpermdi(vf, vf, 1); +// CHECK: shufflevector <2 x i64> %{{[0-9]+}}, <2 x i64> %{{[0-9]+}}, <2 x i32> <i32 0, i32 3> +// CHECK-LE: shufflevector <2 x i64> %{{[0-9]+}}, <2 x i64> %{{[0-9]+}}, <2 x i32> <i32 2, i32 1> + +res_vsll = vec_xxpermdi(vsll, vsll, 2); +// CHECK: shufflevector <2 x i64> %{{[0-9]+}}, <2 x i64> %{{[0-9]+}}, <2 x i32> <i32 1, i32 2> +// CHECK-LE: shufflevector <2 x i64> %{{[0-9]+}}, <2 x i64> %{{[0-9]+}}, <2 x i32> <i32 3, i32 0> + +res_vull = vec_xxpermdi(vull, vull, 3); +// CHECK: shufflevector <2 x i64> %{{[0-9]+}}, <2 x i64> %{{[0-9]+}}, <2 x i32> <i32 1, i32 3> +// CHECK-LE: shufflevector <2 x i64> %{{[0-9]+}}, <2 x i64> %{{[0-9]+}}, <2 x i32> <i32 2, i32 0> + +res_vsi = vec_xxpermdi(vsi, vsi, 0); +// CHECK: shufflevector <2 x i64> %{{[0-9]+}}, <2 x i64> %{{[0-9]+}}, <2 x i32> <i32 0, i32 2> +// CHECK-LE: shufflevector <2 x i64> %{{[0-9]+}}, <2 x i64> %{{[0-9]+}}, <2 x i32> <i32 3, i32 1> + +res_vui = vec_xxpermdi(vui, vui, 1); +// CHECK: shufflevector <2 x i64> %{{[0-9]+}}, <2 x i64> %{{[0-9]+}}, <2 x i32> <i32 0, i32 3> +// CHECK-LE: shufflevector <2 x i64> %{{[0-9]+}}, <2 x i64> %{{[0-9]+}}, <2 x i32> <i32 2, i32 1> + +res_vss = vec_xxpermdi(vss, vss, 2); +// CHECK: shufflevector <2 x i64> %{{[0-9]+}}, <2 x i64> %{{[0-9]+}}, <2 x i32> <i32 1, i32 2> +// CHECK-LE: shufflevector <2 x i64> %{{[0-9]+}}, <2 x i64> %{{[0-9]+}}, <2 x i32> <i32 3, i32 0> + +res_vus = vec_xxpermdi(vus, vus, 3); +// CHECK: shufflevector <2 x i64> %{{[0-9]+}}, <2 x i64> %{{[0-9]+}}, <2 x i32> <i32 1, i32 3> +// CHECK-LE: shufflevector <2 x i64> %{{[0-9]+}}, <2 x i64> %{{[0-9]+}}, <2 x i32> <i32 2, i32 0> + +res_vsc = vec_xxpermdi(vsc, vsc, 0); +// CHECK: shufflevector <2 x i64> %{{[0-9]+}}, <2 x i64> %{{[0-9]+}}, <2 x i32> <i32 0, i32 2> +// CHECK-LE: shufflevector <2 x i64> %{{[0-9]+}}, <2 x i64> %{{[0-9]+}}, <2 x i32> <i32 3, i32 1> + +res_vuc = vec_xxpermdi(vuc, vuc, 1); +// CHECK: shufflevector <2 x i64> %{{[0-9]+}}, <2 x i64> %{{[0-9]+}}, <2 x i32> <i32 0, i32 3> +// CHECK-LE: shufflevector <2 x i64> %{{[0-9]+}}, <2 x i64> %{{[0-9]+}}, <2 x i32> <i32 2, i32 1> } Index: test/CodeGen/builtins-ppc-error.c =================================================================== --- test/CodeGen/builtins-ppc-error.c +++ test/CodeGen/builtins-ppc-error.c @@ -13,8 +13,17 @@ extern vector signed int vsi; extern vector unsigned char vuc; -void testInsertWord1(void) { +void testInsertWord(void) { int index = 5; vector unsigned char v1 = vec_insert4b(vsi, vuc, index); // expected-error {{argument to '__builtin_vsx_insertword' must be a constant integer}} vector unsigned long long v2 = vec_extract4b(vuc, index); // expected-error {{argument to '__builtin_vsx_extractuword' must be a constant integer}} } + +void testXXPERMDI(void) { + int index = 5; + vec_xxpermdi(vsi); //expected-error {{too few arguments to function call, expected at least 3, have 1}} + vec_xxpermdi(vsi, vsi, 2, 4); //expected-error {{too many arguments to function call, expected at most 3, have 4}} + vec_xxpermdi(vsi, vsi, index); //expected-error {{third argument to '__builtin_vsx_xxpermdi' must be a constant integer between 0-3}} + vec_xxpermdi(vsi, vsi, -1); //expected-error {{third argument to '__builtin_vsx_xxpermdi' must be a constant integer between 0-3}} + vec_xxpermdi(vsi, vuc, 2); //expected-error {{first two arguments to '__builtin_vsx_xxpermdi' must be the same type}} +} Index: lib/Sema/SemaChecking.cpp =================================================================== --- lib/Sema/SemaChecking.cpp +++ lib/Sema/SemaChecking.cpp @@ -1696,6 +1696,8 @@ case PPC::BI__builtin_tabortdci: return SemaBuiltinConstantArgRange(TheCall, 0, 0, 31) || SemaBuiltinConstantArgRange(TheCall, 2, 0, 31); + case PPC::BI__builtin_vsx_xxpermdi: + return SemaBuiltinVSX(TheCall, 3); } return SemaBuiltinConstantArgRange(TheCall, i, l, u); } @@ -3888,6 +3890,68 @@ return false; } +// Customized Sema Checking for VSX builtins that have the following signature: +// vector [...] builtinName(vector [...], vector [...], const int); +// Which takes the same type of vectors (any legal vector type) for the first +// two arguments and takes compile time constant (0-3) for the third argument. +// e.g. : +// vector double vec_xxpermdi(vector double, vector double, int); +// vector short vec_xxsldwi(vector short, vector short, int); +bool Sema::SemaBuiltinVSX(CallExpr *TheCall, unsigned NumArgs) { + if (TheCall->getNumArgs() < NumArgs) + return Diag(TheCall->getLocEnd(), + diag::err_typecheck_call_too_few_args_at_least) + << 0 /*function call*/ << NumArgs << TheCall->getNumArgs() + << TheCall->getSourceRange(); + + if (TheCall->getNumArgs() > NumArgs) + return Diag(TheCall->getLocEnd(), + diag::err_typecheck_call_too_many_args_at_most) + << 0 /*function call*/ << NumArgs << TheCall->getNumArgs() + << TheCall->getSourceRange(); + + // Check the third argument is a constant between 0 - 3. + llvm::APSInt Value; + bool IsICE = TheCall->getArg(2)->isIntegerConstantExpr(Value, Context); + if (!(IsICE && Value >= 0 && Value <= 3)) + return Diag(TheCall->getLocStart(), + diag::err_vsx_builtin_nonconstant_argument3) + << TheCall->getDirectCallee() + << SourceRange(TheCall->getArg(2)->getLocStart(), + TheCall->getArg(2)->getLocEnd()); + + QualType Arg1Ty = TheCall->getArg(0)->getType(); + QualType Arg2Ty = TheCall->getArg(1)->getType(); + + // Check the type of argument 1 and argument 2 are vectors. + SourceLocation BuiltinLoc = TheCall->getLocStart(); + if ((!Arg1Ty->isVectorType() && !Arg1Ty->isDependentType()) || + (!Arg2Ty->isVectorType() && !Arg2Ty->isDependentType())) { + return Diag(BuiltinLoc, diag::err_vsx_builtin_arguments_non_vector) + << TheCall->getDirectCallee() + << SourceRange(TheCall->getArg(0)->getLocStart(), + TheCall->getArg(1)->getLocEnd()); + } + + // Check the first two arguments are the same type. + if (!Arg1Ty->isDependentType() && !Arg2Ty->isDependentType()) { + QualType Arg1ElemTy = Arg1Ty->getAs<VectorType>()->getElementType(); + QualType Arg21ElemTy = Arg2Ty->getAs<VectorType>()->getElementType(); + if (Arg1ElemTy != Arg21ElemTy) + return Diag(BuiltinLoc, diag::err_vsx_builtin_incompatible_vector) + << TheCall->getDirectCallee() + << SourceRange(TheCall->getArg(0)->getLocStart(), + TheCall->getArg(1)->getLocEnd()); + } + + // When default clang type checking is turned off and the customized type + // checking is used, the returning type of the function must be explicitly + // set. Otherwise it is _Bool by default. + TheCall->setType(Arg1Ty); + + return false; +} + /// SemaBuiltinShuffleVector - Handle __builtin_shufflevector. // This is declared to take (...), so we have to check everything. ExprResult Sema::SemaBuiltinShuffleVector(CallExpr *TheCall) { @@ -3910,7 +3974,8 @@ if (!LHSType->isVectorType() || !RHSType->isVectorType()) return ExprError(Diag(TheCall->getLocStart(), - diag::err_shufflevector_non_vector) + diag::err_vsx_builtin_arguments_non_vector) + << TheCall->getDirectCallee() << SourceRange(TheCall->getArg(0)->getLocStart(), TheCall->getArg(1)->getLocEnd())); @@ -3924,7 +3989,8 @@ if (!RHSType->hasIntegerRepresentation() || RHSType->getAs<VectorType>()->getNumElements() != numElements) return ExprError(Diag(TheCall->getLocStart(), - diag::err_shufflevector_incompatible_vector) + diag::err_vsx_builtin_incompatible_vector) + << TheCall->getDirectCallee() << SourceRange(TheCall->getArg(1)->getLocStart(), TheCall->getArg(1)->getLocEnd())); } else if (!Context.hasSameUnqualifiedType(LHSType, RHSType)) { Index: lib/Headers/altivec.h =================================================================== --- lib/Headers/altivec.h +++ lib/Headers/altivec.h @@ -12156,6 +12156,10 @@ #endif +#ifdef __VSX__ +#define vec_xxpermdi __builtin_vsx_xxpermdi +#endif + /* vec_xor */ #define __builtin_altivec_vxor vec_xor Index: lib/CodeGen/CGBuiltin.cpp =================================================================== --- lib/CodeGen/CGBuiltin.cpp +++ lib/CodeGen/CGBuiltin.cpp @@ -8404,9 +8404,8 @@ Value *Call = Builder.CreateCall(F, Ops); // Create a shuffle mask of (1, 0) - Constant *ShuffleElts[2] = { ConstantInt::get(Int32Ty, 1), - ConstantInt::get(Int32Ty, 0) - }; + Constant *ShuffleElts[2] = {ConstantInt::get(Int32Ty, 1), + ConstantInt::get(Int32Ty, 0)}; Constant *ShuffleMask = llvm::ConstantVector::get(ShuffleElts); Value *ShuffleCall = Builder.CreateShuffleVector(Call, Call, ShuffleMask); @@ -8416,6 +8415,72 @@ return Builder.CreateCall(F, Ops); } } + + case PPC::BI__builtin_vsx_xxpermdi: { + // Third argument is a compile time constant int. It must be clamped to + // to the range [0, 3]. + ConstantInt *ArgCI = dyn_cast<ConstantInt>(Ops[2]); + assert(ArgCI && "Third arg must be constant integer!"); + const int64_t MaxIndex = 3; + int64_t Index = clamp(ArgCI->getSExtValue(), 0, MaxIndex); + Ops[0] = Builder.CreateBitCast(Ops[0], llvm::VectorType::get(Int64Ty, 2)); + Ops[1] = Builder.CreateBitCast(Ops[1], llvm::VectorType::get(Int64Ty, 2)); + + // Create a shuffle mask + unsigned int ElemIdx0; + unsigned int ElemIdx1; + if (getTarget().isLittleEndian()) { + switch (Index) { + case 0: + ElemIdx0 = 3; + ElemIdx1 = 1; + break; + case 1: + ElemIdx0 = 2; + ElemIdx1 = 1; + break; + case 2: + ElemIdx0 = 3; + ElemIdx1 = 0; + break; + case 3: + ElemIdx0 = 2; + ElemIdx1 = 0; + break; + default: + llvm_unreachable("Wrong argument value!"); + } + } else { // BigEndian + switch (Index) { + case 0: + ElemIdx0 = 0; + ElemIdx1 = 2; + break; + case 1: + ElemIdx0 = 0; + ElemIdx1 = 3; + break; + case 2: + ElemIdx0 = 1; + ElemIdx1 = 2; + break; + case 3: + ElemIdx0 = 1; + ElemIdx1 = 3; + break; + default: + llvm_unreachable("Wrong argument value!"); + } + } + + Constant *ShuffleElts[2] = {ConstantInt::get(Int32Ty, ElemIdx0), + ConstantInt::get(Int32Ty, ElemIdx1)}; + Constant *ShuffleMask = llvm::ConstantVector::get(ShuffleElts); + + Value *ShuffleCall = + Builder.CreateShuffleVector(Ops[0], Ops[1], ShuffleMask); + return ShuffleCall; + } } } Index: include/clang/Sema/Sema.h =================================================================== --- include/clang/Sema/Sema.h +++ include/clang/Sema/Sema.h @@ -10074,6 +10074,7 @@ bool SemaBuiltinVAStartARM(CallExpr *Call); bool SemaBuiltinUnorderedCompare(CallExpr *TheCall); bool SemaBuiltinFPClassification(CallExpr *TheCall, unsigned NumArgs); + bool SemaBuiltinVSX(CallExpr *TheCall, unsigned NumArgs); bool SemaBuiltinOSLogFormat(CallExpr *TheCall); public: Index: include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- include/clang/Basic/DiagnosticSemaKinds.td +++ include/clang/Basic/DiagnosticSemaKinds.td @@ -7994,16 +7994,21 @@ def err_block_on_vm : Error< "__block attribute not allowed on declaration with a variably modified type">; -def err_shufflevector_non_vector : Error< - "first two arguments to __builtin_shufflevector must be vectors">; def err_shufflevector_incompatible_vector : Error< "first two arguments to __builtin_shufflevector must have the same type">; def err_shufflevector_nonconstant_argument : Error< "index for __builtin_shufflevector must be a constant integer">; def err_shufflevector_argument_too_large : Error< "index for __builtin_shufflevector must be less than the total number " "of vector elements">; +def err_vsx_builtin_nonconstant_argument3 : Error< + "third argument to %0 must be a constant integer between 0-3">; +def err_vsx_builtin_arguments_non_vector : Error< + "first two arguments to %0 must be vectors">; +def err_vsx_builtin_incompatible_vector : Error< + "first two arguments to %0 must be the same type">; + def err_convertvector_non_vector : Error< "first argument to __builtin_convertvector must be a vector">; def err_convertvector_non_vector_type : Error< Index: include/clang/Basic/BuiltinsPPC.def =================================================================== --- include/clang/Basic/BuiltinsPPC.def +++ include/clang/Basic/BuiltinsPPC.def @@ -420,6 +420,8 @@ BUILTIN(__builtin_vsx_insertword, "V16UcV4UiV16UcIi", "") BUILTIN(__builtin_vsx_extractuword, "V2ULLiV16UcIi", "") +BUILTIN(__builtin_vsx_xxpermdi, "v.", "t") + // HTM builtins BUILTIN(__builtin_tbegin, "UiUIi", "") BUILTIN(__builtin_tend, "UiUIi", "")
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits