Index: llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp =================================================================== --- llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp +++ llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp @@ -1887,6 +1887,48 @@ return new ICmpInst(NewPred, X, SubOne(cast(Cmp.getOperand(1)))); } + const APInt *C2; + if (And->hasOneUse() && C.isZero() && match(Y, m_APInt(C2))) { + const APInt *C1; + Value *X1; + // ((X1 * C1) & C2) ==/!= 0 -> ((X1 * (C1/C2)) & 1) ==/!= 0 + // iff C2 is a power of 2 greater than 1 and C1 is a multiple of C2 + if (match(X, m_Mul(m_Value(X1), m_APInt(C1))) && C2->isPowerOf2() && + !C2->isOne() && (C1->urem(*C2)).isZero()) { + APInt NewDiv = C1->udiv(*C2); + auto *NewMul = + Builder.CreateMul(X1, ConstantInt::get(X1->getType(), NewDiv)); + auto *NewAnd = + Builder.CreateAnd(NewMul, ConstantInt::get(NewMul->getType(), 1)); + return new ICmpInst(Cmp.getPredicate(), NewAnd, Cmp.getOperand(1)); + } + + Value *X2; + // ((X1 * X2) & C2) ==/!= 0 -> (X1 & C2) ==/!= 0 + // iff (C2 + 1) is a power of 2 and (X2 & C2) == 1 + if (match(X, m_Mul(m_Value(X1), m_Value(X2))) && C2->isMask()) { + unsigned TrailingOnes = C2->countTrailingOnes(); + APInt ExpectedZero = + C2->usub_sat(APInt::getOneBitSet(C2->getBitWidth(), 0)); + + auto Check = [&](Value *Xi, Value *Xj) -> Instruction * { + KnownBits XiKnown = computeKnownBits(Xi, 0, &Cmp); + if (XiKnown.One.getLoBits(1).isOne() && + XiKnown.Zero.getLoBits(TrailingOnes) == ExpectedZero) { + auto *NewAnd = + Builder.CreateAnd(Xj, ConstantInt::get(Xj->getType(), *C2)); + return new ICmpInst(Cmp.getPredicate(), NewAnd, Cmp.getOperand(1)); + } + return nullptr; + }; + + if (Instruction *I = Check(X1, X2)) + return I; + if (Instruction *I = Check(X2, X1)) + return I; + } + } + return nullptr; } Index: llvm/test/Transforms/InstCombine/icmp-mul-and.ll =================================================================== --- llvm/test/Transforms/InstCombine/icmp-mul-and.ll +++ llvm/test/Transforms/InstCombine/icmp-mul-and.ll @@ -22,8 +22,8 @@ ; CHECK-LABEL: @mul_mask_pow2_ne0_use1( ; CHECK-NEXT: [[MUL:%.*]] = mul i8 [[X:%.*]], 40 ; CHECK-NEXT: call void @use(i8 [[MUL]]) -; CHECK-NEXT: [[AND:%.*]] = and i8 [[MUL]], 8 -; CHECK-NEXT: [[CMP:%.*]] = icmp ne i8 [[AND]], 0 +; CHECK-NEXT: [[TMP1:%.*]] = and i8 [[X]], 1 +; CHECK-NEXT: [[CMP:%.*]] = icmp ne i8 [[TMP1]], 0 ; CHECK-NEXT: ret i1 [[CMP]] ; %mul = mul i8 %x, 40 @@ -241,11 +241,8 @@ define i1 @pr51551(i32 %x, i32 %y) { ; CHECK-LABEL: @pr51551( ; CHECK-NEXT: entry: -; CHECK-NEXT: [[TMP0:%.*]] = and i32 [[Y:%.*]], -8 -; CHECK-NEXT: [[TMP1:%.*]] = or i32 [[TMP0]], 1 -; CHECK-NEXT: [[MUL:%.*]] = mul nsw i32 [[TMP1]], [[X:%.*]] -; CHECK-NEXT: [[AND:%.*]] = and i32 [[MUL]], 3 -; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[AND]], 0 +; CHECK-NEXT: [[TMP0:%.*]] = and i32 [[X:%.*]], 3 +; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[TMP0]], 0 ; CHECK-NEXT: ret i1 [[CMP]] ; entry: @@ -260,11 +257,8 @@ define i1 @pr51551_2(i32 %x, i32 %y) { ; CHECK-LABEL: @pr51551_2( ; CHECK-NEXT: entry: -; CHECK-NEXT: [[TMP0:%.*]] = and i32 [[Y:%.*]], -8 -; CHECK-NEXT: [[TMP1:%.*]] = or i32 [[TMP0]], 1 -; CHECK-NEXT: [[MUL:%.*]] = mul nsw i32 [[TMP1]], [[X:%.*]] -; CHECK-NEXT: [[AND:%.*]] = and i32 [[MUL]], 1 -; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[AND]], 0 +; CHECK-NEXT: [[TMP0:%.*]] = and i32 [[X:%.*]], 1 +; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[TMP0]], 0 ; CHECK-NEXT: ret i1 [[CMP]] ; entry: