Index: llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp =================================================================== --- llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp +++ llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp @@ -1771,6 +1771,22 @@ auto NewPred = isICMP_NE ? ICmpInst::ICMP_UGE : ICmpInst::ICMP_ULT; return new ICmpInst(NewPred, X, NegBOC); } + + // ((X1 * MulC) & C2) ==/!= 0 --> (X1 & 1) ==/!= 0 + // iff C2 is a power-of-2 and MulC is a multiple of C2 + Value *X1; + const APInt *MulC; + if (match(X, m_Mul(m_Value(X1), m_APInt(MulC))) && C2->isPowerOf2() && + MulC->urem(*C2).isZero()) { + // To make the transform safe, make sure the mask constant does not + // include bits that must be zero. Demanded bits should clear those bits, + // but it may not have been applied yet. + unsigned MulTZ = MulC->countTrailingZeros(); + if (C2->lshr(MulTZ).shl(MulTZ) == *C2) { + Value *And1 = Builder.CreateAnd(X1, ConstantInt::get(X->getType(), 1)); + return new ICmpInst(Cmp.getPredicate(), And1, Cmp.getOperand(1)); + } + } } // If the LHS is an 'and' of a truncate and we can widen the and/compare to 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 @@ -5,9 +5,8 @@ define i1 @mul_mask_pow2_eq0(i8 %x) { ; CHECK-LABEL: @mul_mask_pow2_eq0( -; CHECK-NEXT: [[MUL:%.*]] = mul i8 [[X:%.*]], 44 -; CHECK-NEXT: [[AND:%.*]] = and i8 [[MUL]], 4 -; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[AND]], 0 +; CHECK-NEXT: [[TMP1:%.*]] = and i8 [[X:%.*]], 1 +; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[TMP1]], 0 ; CHECK-NEXT: ret i1 [[CMP]] ; %mul = mul i8 %x, 44 @@ -16,12 +15,14 @@ ret i1 %cmp } +; extra use of mul is ok. + define i1 @mul_mask_pow2_ne0_use1(i8 %x) { ; 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 @@ -31,6 +32,8 @@ ret i1 %cmp } +; negative test - extra use of 'and' would require more instructions + define i1 @mul_mask_pow2_ne0_use2(i8 %x) { ; CHECK-LABEL: @mul_mask_pow2_ne0_use2( ; CHECK-NEXT: [[MUL:%.*]] = mul i8 [[X:%.*]], 40 @@ -46,11 +49,12 @@ ret i1 %cmp } +; non-equality predicates are converted to equality + define i1 @mul_mask_pow2_sgt0(i8 %x) { ; CHECK-LABEL: @mul_mask_pow2_sgt0( -; CHECK-NEXT: [[MUL:%.*]] = mul i8 [[X:%.*]], 44 -; CHECK-NEXT: [[AND:%.*]] = and i8 [[MUL]], 4 -; 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, 44 @@ -59,11 +63,12 @@ ret i1 %cmp } +; unnecessary mask bits are removed + define i1 @mul_mask_fakepow2_ne0(i8 %x) { ; CHECK-LABEL: @mul_mask_fakepow2_ne0( -; CHECK-NEXT: [[MUL:%.*]] = mul i8 [[X:%.*]], 44 -; CHECK-NEXT: [[AND:%.*]] = and i8 [[MUL]], 4 -; 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, 44 @@ -72,11 +77,12 @@ ret i1 %cmp } +; non-zero cmp constant is converted + define i1 @mul_mask_pow2_eq4(i8 %x) { ; CHECK-LABEL: @mul_mask_pow2_eq4( -; CHECK-NEXT: [[MUL:%.*]] = mul i8 [[X:%.*]], 44 -; CHECK-NEXT: [[AND:%.*]] = and i8 [[MUL]], 4 -; 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, 44 @@ -85,6 +91,8 @@ ret i1 %cmp } +; negative test - must be pow2 mask constant + define i1 @mul_mask_notpow2_ne(i8 %x) { ; CHECK-LABEL: @mul_mask_notpow2_ne( ; CHECK-NEXT: [[MUL:%.*]] = mul i8 [[X:%.*]], 60 @@ -101,9 +109,8 @@ define i1 @pr40493(i32 %area) { ; CHECK-LABEL: @pr40493( ; CHECK-NEXT: entry: -; CHECK-NEXT: [[MUL:%.*]] = mul i32 [[AREA:%.*]], 12 -; CHECK-NEXT: [[REM:%.*]] = and i32 [[MUL]], 4 -; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[REM]], 0 +; CHECK-NEXT: [[TMP0:%.*]] = and i32 [[AREA:%.*]], 1 +; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[TMP0]], 0 ; CHECK-NEXT: ret i1 [[CMP]] ; entry: @@ -159,9 +166,8 @@ define <4 x i1> @pr40493_vec1(<4 x i32> %area) { ; CHECK-LABEL: @pr40493_vec1( ; CHECK-NEXT: entry: -; CHECK-NEXT: [[MUL:%.*]] = mul <4 x i32> [[AREA:%.*]], -; CHECK-NEXT: [[REM:%.*]] = and <4 x i32> [[MUL]], -; CHECK-NEXT: [[CMP:%.*]] = icmp eq <4 x i32> [[REM]], zeroinitializer +; CHECK-NEXT: [[TMP0:%.*]] = and <4 x i32> [[AREA:%.*]], +; CHECK-NEXT: [[CMP:%.*]] = icmp eq <4 x i32> [[TMP0]], zeroinitializer ; CHECK-NEXT: ret <4 x i1> [[CMP]] ; entry: