From aa4fe05939ffbfd746b8f0065cc0b5e06ea94fe2 Mon Sep 17 00:00:00 2001 From: Anton Yartsev Date: Thu, 18 Nov 2010 03:19:30 +0000 Subject: [PATCH] comparison of AltiVec vectors now gives bool result (fix for 7533) git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@119678 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/CodeGen/CGExprScalar.cpp | 108 ++++++++++++++++++++++++++++ lib/Sema/SemaExpr.cpp | 5 ++ test/CodeGen/builtins-ppc-altivec.c | 61 ++++++++++++++++ test/Parser/altivec.c | 10 +++ test/Parser/cxx-altivec.cpp | 26 +++---- test/Sema/altivec-init.c | 2 +- test/SemaCXX/altivec.cpp | 2 +- 7 files changed, 194 insertions(+), 20 deletions(-) diff --git a/lib/CodeGen/CGExprScalar.cpp b/lib/CodeGen/CGExprScalar.cpp index 0e09642931..a5f9890c12 100644 --- a/lib/CodeGen/CGExprScalar.cpp +++ b/lib/CodeGen/CGExprScalar.cpp @@ -1981,6 +1981,48 @@ Value *ScalarExprEmitter::EmitShr(const BinOpInfo &Ops) { return Builder.CreateAShr(Ops.LHS, RHS, "shr"); } +enum IntrinsicType { VCMPEQ, VCMPGT }; +// return corresponding comparison intrinsic for given vector type +static llvm::Intrinsic::ID GetIntrinsic(IntrinsicType IT, + BuiltinType::Kind ElemKind) { + switch (ElemKind) { + default: assert(0 && "unexpected element type"); + case BuiltinType::Char_U: + case BuiltinType::UChar: + return (IT == VCMPEQ) ? llvm::Intrinsic::ppc_altivec_vcmpequb_p : + llvm::Intrinsic::ppc_altivec_vcmpgtub_p; + break; + case BuiltinType::Char_S: + case BuiltinType::SChar: + return (IT == VCMPEQ) ? llvm::Intrinsic::ppc_altivec_vcmpequb_p : + llvm::Intrinsic::ppc_altivec_vcmpgtsb_p; + break; + case BuiltinType::UShort: + return (IT == VCMPEQ) ? llvm::Intrinsic::ppc_altivec_vcmpequh_p : + llvm::Intrinsic::ppc_altivec_vcmpgtuh_p; + break; + case BuiltinType::Short: + return (IT == VCMPEQ) ? llvm::Intrinsic::ppc_altivec_vcmpequh_p : + llvm::Intrinsic::ppc_altivec_vcmpgtsh_p; + break; + case BuiltinType::UInt: + case BuiltinType::ULong: + return (IT == VCMPEQ) ? llvm::Intrinsic::ppc_altivec_vcmpequw_p : + llvm::Intrinsic::ppc_altivec_vcmpgtuw_p; + break; + case BuiltinType::Int: + case BuiltinType::Long: + return (IT == VCMPEQ) ? llvm::Intrinsic::ppc_altivec_vcmpequw_p : + llvm::Intrinsic::ppc_altivec_vcmpgtsw_p; + break; + case BuiltinType::Float: + return (IT == VCMPEQ) ? llvm::Intrinsic::ppc_altivec_vcmpeqfp_p : + llvm::Intrinsic::ppc_altivec_vcmpgtfp_p; + break; + } + return llvm::Intrinsic::not_intrinsic; +} + Value *ScalarExprEmitter::EmitCompare(const BinaryOperator *E,unsigned UICmpOpc, unsigned SICmpOpc, unsigned FCmpOpc) { TestAndClearIgnoreResultAssign(); @@ -1997,6 +2039,72 @@ Value *ScalarExprEmitter::EmitCompare(const BinaryOperator *E,unsigned UICmpOpc, Value *LHS = Visit(E->getLHS()); Value *RHS = Visit(E->getRHS()); + // If AltiVec, the comparison results in a numeric type, so we use + // intrinsics comparing vectors and giving 0 or 1 as a result + if (LHSTy->isVectorType() && CGF.getContext().getLangOptions().AltiVec) { + // constants for mapping CR6 register bits to predicate result + enum { CR6_EQ=0, CR6_EQ_REV, CR6_LT, CR6_LT_REV } CR6; + + llvm::Intrinsic::ID ID = llvm::Intrinsic::not_intrinsic; + + // in several cases vector arguments order will be reversed + Value *FirstVecArg = LHS, + *SecondVecArg = RHS; + + QualType ElTy = LHSTy->getAs()->getElementType(); + Type *Ty = CGF.getContext().getCanonicalType(ElTy).getTypePtr(); + const BuiltinType *BTy = dyn_cast(Ty); + BuiltinType::Kind ElementKind = BTy->getKind(); + + switch(E->getOpcode()) { + default: assert(0 && "is not a comparison operation"); + case BO_EQ: + CR6 = CR6_LT; + ID = GetIntrinsic(VCMPEQ, ElementKind); + break; + case BO_NE: + CR6 = CR6_EQ; + ID = GetIntrinsic(VCMPEQ, ElementKind); + break; + case BO_LT: + CR6 = CR6_LT; + ID = GetIntrinsic(VCMPGT, ElementKind); + std::swap(FirstVecArg, SecondVecArg); + break; + case BO_GT: + CR6 = CR6_LT; + ID = GetIntrinsic(VCMPGT, ElementKind); + break; + case BO_LE: + if (ElementKind == BuiltinType::Float) { + CR6 = CR6_LT; + ID = llvm::Intrinsic::ppc_altivec_vcmpgefp_p; + std::swap(FirstVecArg, SecondVecArg); + } + else { + CR6 = CR6_EQ; + ID = GetIntrinsic(VCMPGT, ElementKind); + } + break; + case BO_GE: + if (ElementKind == BuiltinType::Float) { + CR6 = CR6_LT; + ID = llvm::Intrinsic::ppc_altivec_vcmpgefp_p; + } + else { + CR6 = CR6_EQ; + ID = GetIntrinsic(VCMPGT, ElementKind); + std::swap(FirstVecArg, SecondVecArg); + } + break; + } + + Value *CR6Param = llvm::ConstantInt::get(CGF.Int32Ty, CR6); + llvm::Function *F = CGF.CGM.getIntrinsic(ID); + Result = Builder.CreateCall3(F, CR6Param, FirstVecArg, SecondVecArg, ""); + return EmitScalarConversion(Result, CGF.getContext().BoolTy, E->getType()); + } + if (LHS->getType()->isFPOrFPVectorTy()) { Result = Builder.CreateFCmp((llvm::CmpInst::Predicate)FCmpOpc, LHS, RHS, "cmp"); diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 277da3b78c..2cb92b6db6 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -6423,6 +6423,11 @@ QualType Sema::CheckVectorCompareOperands(Expr *&lex, Expr *&rex, if (vType.isNull()) return vType; + // If AltiVec, the comparison results in a numeric type, i.e. + // bool for C++, int for C + if (getLangOptions().AltiVec) + return (getLangOptions().CPlusPlus ? Context.BoolTy : Context.IntTy); + QualType lType = lex->getType(); QualType rType = rex->getType(); diff --git a/test/CodeGen/builtins-ppc-altivec.c b/test/CodeGen/builtins-ppc-altivec.c index e4717d9da6..fbc3148dda 100644 --- a/test/CodeGen/builtins-ppc-altivec.c +++ b/test/CodeGen/builtins-ppc-altivec.c @@ -3052,3 +3052,64 @@ void test6() { /* vec_any_out */ res_i = vec_any_out(vf, vf); // CHECK: @llvm.ppc.altivec.vcmpbfp.p } + +/* ------------------------------ Relational Operators------------------------------- */ +// CHECK: define void @test7 +void test7() { + vector signed char vsc1 = (vector signed char)(-1); + vector signed char vsc2 = (vector signed char)(-2); + res_i = (vsc1 == vsc2); // CHECK: @llvm.ppc.altivec.vcmpequb.p(i32 2 + res_i = (vsc1 != vsc2); // CHECK: @llvm.ppc.altivec.vcmpequb.p(i32 0 + res_i = (vsc1 < vsc2); // CHECK: @llvm.ppc.altivec.vcmpgtsb.p(i32 2 + res_i = (vsc1 > vsc2); // CHECK: @llvm.ppc.altivec.vcmpgtsb.p(i32 2 + res_i = (vsc1 <= vsc2); // CHECK: @llvm.ppc.altivec.vcmpgtsb.p(i32 0 + res_i = (vsc1 >= vsc2); // CHECK: @llvm.ppc.altivec.vcmpgtsb.p(i32 0 + vector unsigned char vuc1 = (vector unsigned char)(1); + vector unsigned char vuc2 = (vector unsigned char)(2); + res_i = (vuc1 == vuc2); // CHECK: @llvm.ppc.altivec.vcmpequb.p(i32 2 + res_i = (vuc1 != vuc2); // CHECK: @llvm.ppc.altivec.vcmpequb.p(i32 0 + res_i = (vuc1 < vuc2); // CHECK: @llvm.ppc.altivec.vcmpgtub.p(i32 2 + res_i = (vuc1 > vuc2); // CHECK: @llvm.ppc.altivec.vcmpgtub.p(i32 2 + res_i = (vuc1 <= vuc2); // CHECK: @llvm.ppc.altivec.vcmpgtub.p(i32 0 + res_i = (vuc1 >= vuc2); // CHECK: @llvm.ppc.altivec.vcmpgtub.p(i32 0 + vector short vs1 = (vector short)(-1); + vector short vs2 = (vector short)(-2); + res_i = (vs1 == vs2); // CHECK: @llvm.ppc.altivec.vcmpequh.p(i32 2 + res_i = (vs1 != vs2); // CHECK: @llvm.ppc.altivec.vcmpequh.p(i32 0 + res_i = (vs1 < vs2); // CHECK: @llvm.ppc.altivec.vcmpgtsh.p(i32 2 + res_i = (vs1 > vs2); // CHECK: @llvm.ppc.altivec.vcmpgtsh.p(i32 2 + res_i = (vs1 <= vs2); // CHECK: @llvm.ppc.altivec.vcmpgtsh.p(i32 0 + res_i = (vs1 >= vs2); // CHECK: @llvm.ppc.altivec.vcmpgtsh.p(i32 0 + vector unsigned short vus1 = (vector unsigned short)(1); + vector unsigned short vus2 = (vector unsigned short)(2); + res_i = (vus1 == vus2); // CHECK: @llvm.ppc.altivec.vcmpequh.p(i32 2 + res_i = (vus1 != vus2); // CHECK: @llvm.ppc.altivec.vcmpequh.p(i32 0 + res_i = (vus1 < vus2); // CHECK: @llvm.ppc.altivec.vcmpgtuh.p(i32 2 + res_i = (vus1 > vus2); // CHECK: @llvm.ppc.altivec.vcmpgtuh.p(i32 2 + res_i = (vus1 <= vus2); // CHECK: @llvm.ppc.altivec.vcmpgtuh.p(i32 0 + res_i = (vus1 >= vus2); // CHECK: @llvm.ppc.altivec.vcmpgtuh.p(i32 0 + vector int vi1 = (vector int)(-1); + vector int vi2 = (vector int)(-2); + res_i = (vi1 == vi2); // CHECK: @llvm.ppc.altivec.vcmpequw.p(i32 2 + res_i = (vi1 != vi2); // CHECK: @llvm.ppc.altivec.vcmpequw.p(i32 0 + res_i = (vi1 < vi2); // CHECK: @llvm.ppc.altivec.vcmpgtsw.p(i32 2 + res_i = (vi1 > vi2); // CHECK: @llvm.ppc.altivec.vcmpgtsw.p(i32 2 + res_i = (vi1 <= vi2); // CHECK: @llvm.ppc.altivec.vcmpgtsw.p(i32 0 + res_i = (vi1 >= vi2); // CHECK: @llvm.ppc.altivec.vcmpgtsw.p(i32 0 + vector unsigned int vui1 = (vector unsigned int)(1); + vector unsigned int vui2 = (vector unsigned int)(2); + res_i = (vui1 == vui2); // CHECK: @llvm.ppc.altivec.vcmpequw.p(i32 2 + res_i = (vui1 != vui2); // CHECK: @llvm.ppc.altivec.vcmpequw.p(i32 0 + res_i = (vui1 < vui2); // CHECK: @llvm.ppc.altivec.vcmpgtuw.p(i32 2 + res_i = (vui1 > vui2); // CHECK: @llvm.ppc.altivec.vcmpgtuw.p(i32 2 + res_i = (vui1 <= vui2); // CHECK: @llvm.ppc.altivec.vcmpgtuw.p(i32 0 + res_i = (vui1 >= vui2); // CHECK: @llvm.ppc.altivec.vcmpgtuw.p(i32 0 + vector float vf1 = (vector float)(1.0); + vector float vf2 = (vector float)(2.0); + res_i = (vf1 == vf2); // CHECK: @llvm.ppc.altivec.vcmpeqfp.p(i32 2 + res_i = (vf1 != vf2); // CHECK: @llvm.ppc.altivec.vcmpeqfp.p(i32 0 + res_i = (vf1 < vf2); // CHECK: @llvm.ppc.altivec.vcmpgtfp.p(i32 2 + res_i = (vf1 > vf2); // CHECK: @llvm.ppc.altivec.vcmpgtfp.p(i32 2 + res_i = (vf1 <= vf2); // CHECK: @llvm.ppc.altivec.vcmpgefp.p(i32 2 + res_i = (vf1 >= vf2); // CHECK: @llvm.ppc.altivec.vcmpgefp.p(i32 2 +} diff --git a/test/Parser/altivec.c b/test/Parser/altivec.c index 92ec688bc0..64f82f7a56 100644 --- a/test/Parser/altivec.c +++ b/test/Parser/altivec.c @@ -100,6 +100,16 @@ void f() { __vector unsigned int tv = gccv; gccv = v; gccvector unsigned int tgv = v; + + int res_i; + // bug 7553 - Problem with '==' and vectors + res_i = (vv_sc == vv_sc); + res_i = (vv_uc != vv_uc); + res_i = (vv_s > vv_s); + res_i = (vv_us >= vv_us); + res_i = (vv_i < vv_i); + res_i = (vv_ui <= vv_ui); + res_i = (vv_f <= vv_f); } // bug 6895 - Vectorl literal casting confusion. diff --git a/test/Parser/cxx-altivec.cpp b/test/Parser/cxx-altivec.cpp index 0ceb9f2e80..4d924503bb 100644 --- a/test/Parser/cxx-altivec.cpp +++ b/test/Parser/cxx-altivec.cpp @@ -127,27 +127,17 @@ vector int v4 = (vector int)(1, 2, 3, 4); vector float v5 = (vector float)(1.0f, 2.0f, 3.0f, 4.0f); vector char v6 = (vector char)((vector int)(1+2, -2, (int)(2.0 * 3), -(5-3))); -#if 0 // Not ready yet. // bug 7553 - Problem with '==' and vectors void func() { - vector int v10i = (vector int)(1, 2, 3, 4); - vector int v11i = (vector int)(1, 2, 3, 4); - bool r10ieq = (v10i == v11i); - bool r10ine = (v10i != v11i); - bool r10igt = (v10i > v11i); - bool r10ige = (v10i >= v11i); - bool r10ilt = (v10i < v11i); - bool r10ile = (v10i <= v11i); - vector float v10f = (vector float)(1.0f, 2.0f, 3.0f, 4.0f); - vector float v11f = (vector float)(1.0f, 2.0f, 3.0f, 4.0f); - bool r10feq = (v10f == v11f); - bool r10fne = (v10f != v11f); - bool r10fgt = (v10f > v11f); - bool r10fge = (v10f >= v11f); - bool r10flt = (v10f < v11f); - bool r10fle = (v10f <= v11f); + bool res_b; + res_b = (vv_sc == vv_sc); + res_b = (vv_uc != vv_uc); + res_b = (vv_s > vv_s); + res_b = (vv_us >= vv_us); + res_b = (vv_i < vv_i); + res_b = (vv_ui <= vv_ui); + res_b = (vv_f <= vv_f); } -#endif // vecreturn attribute test struct Vector diff --git a/test/Sema/altivec-init.c b/test/Sema/altivec-init.c index b5758bc718..ef6fe4bd9d 100644 --- a/test/Sema/altivec-init.c +++ b/test/Sema/altivec-init.c @@ -30,6 +30,6 @@ void test() f(vAltiVec); vGCC = vAltiVec; - vGCC = vGCC > vAltiVec; + int res = vGCC > vAltiVec; vAltiVec = 0 ? vGCC : vGCC; } diff --git a/test/SemaCXX/altivec.cpp b/test/SemaCXX/altivec.cpp index cdfc00a5d4..bb7473f742 100644 --- a/test/SemaCXX/altivec.cpp +++ b/test/SemaCXX/altivec.cpp @@ -13,6 +13,6 @@ void test() f(vAltiVec); vGCC = vAltiVec; - vGCC = vGCC > vAltiVec; + bool res = vGCC > vAltiVec; vAltiVec = 0 ? vGCC : vGCC; } -- 2.40.0