From 2c15995350683056b88145dbededaee5cf94cb42 Mon Sep 17 00:00:00 2001 From: Sanjay Patel Date: Sun, 28 Aug 2016 18:18:00 +0000 Subject: [PATCH] [InstCombine] use m_APInt to allow icmp (and X, Y), C folds for splat constant vectors git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@279937 91177308-0d34-0410-b5e6-96231b3b80d8 --- .../InstCombine/InstCombineCompares.cpp | 64 ++++++++++--------- test/Transforms/InstCombine/and-compare.ll | 10 ++- test/Transforms/InstCombine/apint-shift.ll | 4 +- test/Transforms/InstCombine/icmp.ll | 8 +-- test/Transforms/InstCombine/shift.ll | 4 +- 5 files changed, 41 insertions(+), 49 deletions(-) diff --git a/lib/Transforms/InstCombine/InstCombineCompares.cpp b/lib/Transforms/InstCombine/InstCombineCompares.cpp index b0802a32c9b..81dcbb761db 100644 --- a/lib/Transforms/InstCombine/InstCombineCompares.cpp +++ b/lib/Transforms/InstCombine/InstCombineCompares.cpp @@ -1610,48 +1610,50 @@ Instruction *InstCombiner::foldICmpAndConstant(ICmpInst &Cmp, if (Instruction *I = foldICmpAndConstConst(Cmp, And, C)) return I; - // FIXME: This check restricts all folds under here to scalar types. - ConstantInt *RHS = dyn_cast(Cmp.getOperand(1)); - if (!RHS) - return nullptr; + // TODO: These all require that Y is constant too, so refactor with the above. - // Try to optimize things like "A[i]&42 == 0" to index computations. - if (LoadInst *LI = dyn_cast(And->getOperand(0))) { - if (GetElementPtrInst *GEP = dyn_cast(LI->getOperand(0))) - if (GlobalVariable *GV = dyn_cast(GEP->getOperand(0))) + // Try to optimize things like "A[i] & 42 == 0" to index computations. + Value *X = And->getOperand(0); + Value *Y = And->getOperand(1); + if (auto *LI = dyn_cast(X)) + if (auto *GEP = dyn_cast(LI->getOperand(0))) + if (auto *GV = dyn_cast(GEP->getOperand(0))) if (GV->isConstant() && GV->hasDefinitiveInitializer() && - !LI->isVolatile() && isa(And->getOperand(1))) { - ConstantInt *C = cast(And->getOperand(1)); - if (Instruction *Res = foldCmpLoadFromIndexedGlobal(GEP, GV, Cmp, C)) + !LI->isVolatile() && isa(Y)) { + ConstantInt *C2 = cast(Y); + if (Instruction *Res = foldCmpLoadFromIndexedGlobal(GEP, GV, Cmp, C2)) return Res; } - } + + if (!Cmp.isEquality()) + return nullptr; // X & -C == -C -> X > u ~C // X & -C != -C -> X <= u ~C // iff C is a power of 2 - if (Cmp.isEquality() && RHS == And->getOperand(1) && (-(*C)).isPowerOf2()) - return new ICmpInst(Cmp.getPredicate() == ICmpInst::ICMP_EQ - ? ICmpInst::ICMP_UGT - : ICmpInst::ICMP_ULE, - And->getOperand(0), SubOne(RHS)); + if (Cmp.getOperand(1) == Y && (-(*C)).isPowerOf2()) { + auto NewPred = Cmp.getPredicate() == CmpInst::ICMP_EQ ? CmpInst::ICMP_UGT + : CmpInst::ICMP_ULE; + return new ICmpInst(NewPred, X, SubOne(cast(Cmp.getOperand(1)))); + } - // (icmp eq (and %A, C), 0) -> (icmp sgt (trunc %A), -1) - // iff C is a power of 2 - if (Cmp.isEquality() && And->hasOneUse() && match(RHS, m_Zero())) { - if (auto *CI = dyn_cast(And->getOperand(1))) { - const APInt &AI = CI->getValue(); - int32_t ExactLogBase2 = AI.exactLogBase2(); - if (ExactLogBase2 != -1 && DL.isLegalInteger(ExactLogBase2 + 1)) { - Type *NTy = IntegerType::get(Cmp.getContext(), ExactLogBase2 + 1); - Value *Trunc = Builder->CreateTrunc(And->getOperand(0), NTy); - return new ICmpInst(Cmp.getPredicate() == ICmpInst::ICMP_EQ - ? ICmpInst::ICMP_SGE - : ICmpInst::ICMP_SLT, - Trunc, Constant::getNullValue(NTy)); - } + // (X & C2) == 0 -> (trunc X) >= 0 + // (X & C2) != 0 -> (trunc X) < 0 + // iff C2 is a power of 2 and it masks the sign bit of a legal integer type. + const APInt *C2; + if (And->hasOneUse() && *C == 0 && match(Y, m_APInt(C2))) { + int32_t ExactLogBase2 = C2->exactLogBase2(); + if (ExactLogBase2 != -1 && DL.isLegalInteger(ExactLogBase2 + 1)) { + Type *NTy = IntegerType::get(Cmp.getContext(), ExactLogBase2 + 1); + if (And->getType()->isVectorTy()) + NTy = VectorType::get(NTy, And->getType()->getVectorNumElements()); + Value *Trunc = Builder->CreateTrunc(X, NTy); + auto NewPred = Cmp.getPredicate() == CmpInst::ICMP_EQ ? CmpInst::ICMP_SGE + : CmpInst::ICMP_SLT; + return new ICmpInst(NewPred, Trunc, Constant::getNullValue(NTy)); } } + return nullptr; } diff --git a/test/Transforms/InstCombine/and-compare.ll b/test/Transforms/InstCombine/and-compare.ll index ce6894f9b8e..d4aa1c5488b 100644 --- a/test/Transforms/InstCombine/and-compare.ll +++ b/test/Transforms/InstCombine/and-compare.ll @@ -42,11 +42,10 @@ define i1 @test2(i64 %A) { ret i1 %cmp } -; FIXME: Vectors should fold the same way. define <2 x i1> @test2vec(<2 x i64> %A) { ; CHECK-LABEL: @test2vec( -; CHECK-NEXT: [[AND:%.*]] = and <2 x i64> %A, -; CHECK-NEXT: [[CMP:%.*]] = icmp eq <2 x i64> [[AND]], zeroinitializer +; CHECK-NEXT: [[TMP1:%.*]] = trunc <2 x i64> %A to <2 x i8> +; CHECK-NEXT: [[CMP:%.*]] = icmp sgt <2 x i8> [[TMP1]], ; CHECK-NEXT: ret <2 x i1> [[CMP]] ; %and = and <2 x i64> %A, @@ -65,11 +64,10 @@ define i1 @test3(i64 %A) { ret i1 %cmp } -; FIXME: Vectors should fold the same way. define <2 x i1> @test3vec(<2 x i64> %A) { ; CHECK-LABEL: @test3vec( -; CHECK-NEXT: [[AND:%.*]] = and <2 x i64> %A, -; CHECK-NEXT: [[CMP:%.*]] = icmp ne <2 x i64> [[AND]], zeroinitializer +; CHECK-NEXT: [[TMP1:%.*]] = trunc <2 x i64> %A to <2 x i8> +; CHECK-NEXT: [[CMP:%.*]] = icmp slt <2 x i8> [[TMP1]], zeroinitializer ; CHECK-NEXT: ret <2 x i1> [[CMP]] ; %and = and <2 x i64> %A, diff --git a/test/Transforms/InstCombine/apint-shift.ll b/test/Transforms/InstCombine/apint-shift.ll index 3e1699ab158..50fbe7481a0 100644 --- a/test/Transforms/InstCombine/apint-shift.ll +++ b/test/Transforms/InstCombine/apint-shift.ll @@ -280,11 +280,9 @@ define i1 @test19a(i39 %A) { ret i1 %C } -; FIXME: Vectors should fold too. define <2 x i1> @test19a_vec(<2 x i39> %A) { ; CHECK-LABEL: @test19a_vec( -; CHECK-NEXT: [[B_MASK:%.*]] = and <2 x i39> %A, -; CHECK-NEXT: [[C:%.*]] = icmp eq <2 x i39> [[B_MASK]], +; CHECK-NEXT: [[C:%.*]] = icmp ugt <2 x i39> %A, ; CHECK-NEXT: ret <2 x i1> [[C]] ; %B = ashr <2 x i39> %A, diff --git a/test/Transforms/InstCombine/icmp.ll b/test/Transforms/InstCombine/icmp.ll index a8d55b13c26..93e0cdf3646 100644 --- a/test/Transforms/InstCombine/icmp.ll +++ b/test/Transforms/InstCombine/icmp.ll @@ -1815,11 +1815,9 @@ define i1 @icmp_and_X_-16_eq-16(i32 %X) { ret i1 %cmp } -; FIXME: Vectors should fold the same way. define <2 x i1> @icmp_and_X_-16_eq-16_vec(<2 x i32> %X) { ; CHECK-LABEL: @icmp_and_X_-16_eq-16_vec( -; CHECK-NEXT: [[AND:%.*]] = and <2 x i32> %X, -; CHECK-NEXT: [[CMP:%.*]] = icmp eq <2 x i32> [[AND]], +; CHECK-NEXT: [[CMP:%.*]] = icmp ugt <2 x i32> %X, ; CHECK-NEXT: ret <2 x i1> [[CMP]] ; %and = and <2 x i32> %X, @@ -1837,11 +1835,9 @@ define i1 @icmp_and_X_-16_ne-16(i32 %X) { ret i1 %cmp } -; FIXME: Vectors should fold the same way. define <2 x i1> @icmp_and_X_-16_ne-16_vec(<2 x i32> %X) { ; CHECK-LABEL: @icmp_and_X_-16_ne-16_vec( -; CHECK-NEXT: [[AND:%.*]] = and <2 x i32> %X, -; CHECK-NEXT: [[CMP:%.*]] = icmp ne <2 x i32> [[AND]], +; CHECK-NEXT: [[CMP:%.*]] = icmp ult <2 x i32> %X, ; CHECK-NEXT: ret <2 x i1> [[CMP]] ; %and = and <2 x i32> %X, diff --git a/test/Transforms/InstCombine/shift.ll b/test/Transforms/InstCombine/shift.ll index a91038f9eff..462950671e3 100644 --- a/test/Transforms/InstCombine/shift.ll +++ b/test/Transforms/InstCombine/shift.ll @@ -373,11 +373,9 @@ define i1 @test19a(i32 %A) { ret i1 %C } -; FIXME: Vectors should fold the same way. define <2 x i1> @test19a_vec(<2 x i32> %A) { ; CHECK-LABEL: @test19a_vec( -; CHECK-NEXT: [[B_MASK:%.*]] = and <2 x i32> %A, -; CHECK-NEXT: [[C:%.*]] = icmp eq <2 x i32> [[B_MASK]], +; CHECK-NEXT: [[C:%.*]] = icmp ugt <2 x i32> %A, ; CHECK-NEXT: ret <2 x i1> [[C]] ; %B = ashr <2 x i32> %A,