diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp --- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp @@ -4110,6 +4110,30 @@ return getKnownSign(Op, CxtI, DL, AC, DT, Known); } +static Instruction *foldICmpAndXX(ICmpInst &I, const SimplifyQuery &Q, + InstCombinerImpl &IC) { + Value *Op0 = I.getOperand(0), *Op1 = I.getOperand(1), *A; + // Normalize and operand as operand 0. + CmpInst::Predicate Pred = I.getPredicate(); + if (match(Op1, m_c_And(m_Specific(Op0), m_Value()))) { + std::swap(Op0, Op1); + Pred = ICmpInst::getSwappedPredicate(Pred); + } + + if (!match(Op0, m_c_And(m_Specific(Op1), m_Value(A)))) + return nullptr; + + // (icmp (X & Y) u< X --> (X & Y) != X + if (Pred == ICmpInst::ICMP_ULT) + return new ICmpInst(ICmpInst::ICMP_NE, Op0, Op1); + + // (icmp (X & Y) u>= X --> (X & Y) == X + if (Pred == ICmpInst::ICMP_UGE) + return new ICmpInst(ICmpInst::ICMP_EQ, Op0, Op1); + + return nullptr; +} + static Instruction *foldICmpOrXX(ICmpInst &I, const SimplifyQuery &Q, InstCombinerImpl &IC) { Value *Op0 = I.getOperand(0), *Op1 = I.getOperand(1), *A; @@ -4569,6 +4593,8 @@ return R; if (Instruction *R = foldICmpOrXX(I, Q, *this)) return R; + if (Instruction *R = foldICmpAndXX(I, Q, *this)) + return R; { // Try to remove shared multiplier from comparison: diff --git a/llvm/test/Transforms/InstCombine/canonicalize-constant-low-bit-mask-and-icmp-uge-to-icmp-ule.ll b/llvm/test/Transforms/InstCombine/canonicalize-constant-low-bit-mask-and-icmp-uge-to-icmp-ule.ll --- a/llvm/test/Transforms/InstCombine/canonicalize-constant-low-bit-mask-and-icmp-uge-to-icmp-ule.ll +++ b/llvm/test/Transforms/InstCombine/canonicalize-constant-low-bit-mask-and-icmp-uge-to-icmp-ule.ll @@ -60,16 +60,6 @@ ret <2 x i1> %ret } -define <2 x i1> @p2_vec_nonsplat_edgecase0(<2 x i8> %x) { -; CHECK-LABEL: @p2_vec_nonsplat_edgecase0( -; CHECK-NEXT: [[TMP0:%.*]] = and <2 x i8> [[X:%.*]], -; CHECK-NEXT: [[RET:%.*]] = icmp uge <2 x i8> [[TMP0]], [[X]] -; CHECK-NEXT: ret <2 x i1> [[RET]] -; - %tmp0 = and <2 x i8> %x, - %ret = icmp uge <2 x i8> %tmp0, %x - ret <2 x i1> %ret -} define <2 x i1> @p2_vec_nonsplat_edgecase1(<2 x i8> %x) { ; CHECK-LABEL: @p2_vec_nonsplat_edgecase1( ; CHECK-NEXT: [[TMP1:%.*]] = icmp ule <2 x i8> [[X:%.*]], @@ -176,7 +166,7 @@ define i1 @n0(i8 %x) { ; CHECK-LABEL: @n0( ; CHECK-NEXT: [[TMP0:%.*]] = and i8 [[X:%.*]], 4 -; CHECK-NEXT: [[RET:%.*]] = icmp uge i8 [[TMP0]], [[X]] +; CHECK-NEXT: [[RET:%.*]] = icmp eq i8 [[TMP0]], [[X]] ; CHECK-NEXT: ret i1 [[RET]] ; %tmp0 = and i8 %x, 4 ; power-of-two, but invalid. @@ -198,7 +188,7 @@ define <2 x i1> @n2(<2 x i8> %x) { ; CHECK-LABEL: @n2( ; CHECK-NEXT: [[TMP0:%.*]] = and <2 x i8> [[X:%.*]], -; CHECK-NEXT: [[RET:%.*]] = icmp uge <2 x i8> [[TMP0]], [[X]] +; CHECK-NEXT: [[RET:%.*]] = icmp eq <2 x i8> [[TMP0]], [[X]] ; CHECK-NEXT: ret <2 x i1> [[RET]] ; %tmp0 = and <2 x i8> %x, ; only the first one is valid. diff --git a/llvm/test/Transforms/InstCombine/canonicalize-constant-low-bit-mask-and-icmp-ugt-to-icmp-ugt.ll b/llvm/test/Transforms/InstCombine/canonicalize-constant-low-bit-mask-and-icmp-ugt-to-icmp-ugt.ll --- a/llvm/test/Transforms/InstCombine/canonicalize-constant-low-bit-mask-and-icmp-ugt-to-icmp-ugt.ll +++ b/llvm/test/Transforms/InstCombine/canonicalize-constant-low-bit-mask-and-icmp-ugt-to-icmp-ugt.ll @@ -76,7 +76,7 @@ ; CHECK-LABEL: @p2_vec_nonsplat_edgecase0( ; CHECK-NEXT: [[X:%.*]] = call <2 x i8> @gen2x8() ; CHECK-NEXT: [[TMP0:%.*]] = and <2 x i8> [[X]], -; CHECK-NEXT: [[RET:%.*]] = icmp ugt <2 x i8> [[X]], [[TMP0]] +; CHECK-NEXT: [[RET:%.*]] = icmp ne <2 x i8> [[TMP0]], [[X]] ; CHECK-NEXT: ret <2 x i1> [[RET]] ; %x = call <2 x i8> @gen2x8() @@ -202,7 +202,7 @@ ; CHECK-LABEL: @n0( ; CHECK-NEXT: [[X:%.*]] = call i8 @gen8() ; CHECK-NEXT: [[TMP0:%.*]] = and i8 [[X]], 4 -; CHECK-NEXT: [[RET:%.*]] = icmp ugt i8 [[X]], [[TMP0]] +; CHECK-NEXT: [[RET:%.*]] = icmp ne i8 [[TMP0]], [[X]] ; CHECK-NEXT: ret i1 [[RET]] ; %x = call i8 @gen8() @@ -228,7 +228,7 @@ ; CHECK-LABEL: @n2( ; CHECK-NEXT: [[X:%.*]] = call <2 x i8> @gen2x8() ; CHECK-NEXT: [[TMP0:%.*]] = and <2 x i8> [[X]], -; CHECK-NEXT: [[RET:%.*]] = icmp ugt <2 x i8> [[X]], [[TMP0]] +; CHECK-NEXT: [[RET:%.*]] = icmp ne <2 x i8> [[TMP0]], [[X]] ; CHECK-NEXT: ret <2 x i1> [[RET]] ; %x = call <2 x i8> @gen2x8() diff --git a/llvm/test/Transforms/InstCombine/canonicalize-constant-low-bit-mask-and-icmp-ule-to-icmp-ule.ll b/llvm/test/Transforms/InstCombine/canonicalize-constant-low-bit-mask-and-icmp-ule-to-icmp-ule.ll --- a/llvm/test/Transforms/InstCombine/canonicalize-constant-low-bit-mask-and-icmp-ule-to-icmp-ule.ll +++ b/llvm/test/Transforms/InstCombine/canonicalize-constant-low-bit-mask-and-icmp-ule-to-icmp-ule.ll @@ -76,7 +76,7 @@ ; CHECK-LABEL: @p2_vec_nonsplat_edgecase0( ; CHECK-NEXT: [[X:%.*]] = call <2 x i8> @gen2x8() ; CHECK-NEXT: [[TMP0:%.*]] = and <2 x i8> [[X]], -; CHECK-NEXT: [[RET:%.*]] = icmp ule <2 x i8> [[X]], [[TMP0]] +; CHECK-NEXT: [[RET:%.*]] = icmp eq <2 x i8> [[TMP0]], [[X]] ; CHECK-NEXT: ret <2 x i1> [[RET]] ; %x = call <2 x i8> @gen2x8() @@ -190,7 +190,7 @@ ; CHECK-LABEL: @n0( ; CHECK-NEXT: [[X:%.*]] = call i8 @gen8() ; CHECK-NEXT: [[TMP0:%.*]] = and i8 [[X]], 4 -; CHECK-NEXT: [[RET:%.*]] = icmp ule i8 [[X]], [[TMP0]] +; CHECK-NEXT: [[RET:%.*]] = icmp eq i8 [[TMP0]], [[X]] ; CHECK-NEXT: ret i1 [[RET]] ; %x = call i8 @gen8() @@ -216,7 +216,7 @@ ; CHECK-LABEL: @n2( ; CHECK-NEXT: [[X:%.*]] = call <2 x i8> @gen2x8() ; CHECK-NEXT: [[TMP0:%.*]] = and <2 x i8> [[X]], -; CHECK-NEXT: [[RET:%.*]] = icmp ule <2 x i8> [[X]], [[TMP0]] +; CHECK-NEXT: [[RET:%.*]] = icmp eq <2 x i8> [[TMP0]], [[X]] ; CHECK-NEXT: ret <2 x i1> [[RET]] ; %x = call <2 x i8> @gen2x8() diff --git a/llvm/test/Transforms/InstCombine/canonicalize-constant-low-bit-mask-and-icmp-ult-to-icmp-ugt.ll b/llvm/test/Transforms/InstCombine/canonicalize-constant-low-bit-mask-and-icmp-ult-to-icmp-ugt.ll --- a/llvm/test/Transforms/InstCombine/canonicalize-constant-low-bit-mask-and-icmp-ult-to-icmp-ugt.ll +++ b/llvm/test/Transforms/InstCombine/canonicalize-constant-low-bit-mask-and-icmp-ult-to-icmp-ugt.ll @@ -63,7 +63,7 @@ define <2 x i1> @p2_vec_nonsplat_edgecase0(<2 x i8> %x) { ; CHECK-LABEL: @p2_vec_nonsplat_edgecase0( ; CHECK-NEXT: [[TMP0:%.*]] = and <2 x i8> [[X:%.*]], -; CHECK-NEXT: [[RET:%.*]] = icmp ult <2 x i8> [[TMP0]], [[X]] +; CHECK-NEXT: [[RET:%.*]] = icmp ne <2 x i8> [[TMP0]], [[X]] ; CHECK-NEXT: ret <2 x i1> [[RET]] ; %tmp0 = and <2 x i8> %x, @@ -187,7 +187,7 @@ define i1 @n0(i8 %x) { ; CHECK-LABEL: @n0( ; CHECK-NEXT: [[TMP0:%.*]] = and i8 [[X:%.*]], 4 -; CHECK-NEXT: [[RET:%.*]] = icmp ult i8 [[TMP0]], [[X]] +; CHECK-NEXT: [[RET:%.*]] = icmp ne i8 [[TMP0]], [[X]] ; CHECK-NEXT: ret i1 [[RET]] ; %tmp0 = and i8 %x, 4 ; power-of-two, but invalid. @@ -209,7 +209,7 @@ define <2 x i1> @n2(<2 x i8> %x) { ; CHECK-LABEL: @n2( ; CHECK-NEXT: [[TMP0:%.*]] = and <2 x i8> [[X:%.*]], -; CHECK-NEXT: [[RET:%.*]] = icmp ult <2 x i8> [[TMP0]], [[X]] +; CHECK-NEXT: [[RET:%.*]] = icmp ne <2 x i8> [[TMP0]], [[X]] ; CHECK-NEXT: ret <2 x i1> [[RET]] ; %tmp0 = and <2 x i8> %x, ; only the first one is valid. diff --git a/llvm/test/Transforms/InstCombine/icmp-of-and-x.ll b/llvm/test/Transforms/InstCombine/icmp-of-and-x.ll --- a/llvm/test/Transforms/InstCombine/icmp-of-and-x.ll +++ b/llvm/test/Transforms/InstCombine/icmp-of-and-x.ll @@ -7,7 +7,7 @@ define i1 @icmp_ult_x_y(i8 %x, i8 %y) { ; CHECK-LABEL: @icmp_ult_x_y( ; CHECK-NEXT: [[AND:%.*]] = and i8 [[X:%.*]], [[Y:%.*]] -; CHECK-NEXT: [[Z:%.*]] = icmp ult i8 [[AND]], [[X]] +; CHECK-NEXT: [[Z:%.*]] = icmp ne i8 [[AND]], [[X]] ; CHECK-NEXT: ret i1 [[Z]] ; %and = and i8 %x, %y @@ -19,7 +19,7 @@ ; CHECK-LABEL: @icmp_ult_x_y_2( ; CHECK-NEXT: [[X:%.*]] = mul i8 [[XX:%.*]], [[XX]] ; CHECK-NEXT: [[AND:%.*]] = and i8 [[X]], [[Y:%.*]] -; CHECK-NEXT: [[Z:%.*]] = icmp ugt i8 [[X]], [[AND]] +; CHECK-NEXT: [[Z:%.*]] = icmp ne i8 [[AND]], [[X]] ; CHECK-NEXT: ret i1 [[Z]] ; %x = mul i8 %xx, %xx @@ -31,7 +31,7 @@ define <2 x i1> @icmp_uge_x_y(<2 x i8> %x, <2 x i8> %y) { ; CHECK-LABEL: @icmp_uge_x_y( ; CHECK-NEXT: [[AND:%.*]] = and <2 x i8> [[X:%.*]], [[Y:%.*]] -; CHECK-NEXT: [[Z:%.*]] = icmp uge <2 x i8> [[AND]], [[X]] +; CHECK-NEXT: [[Z:%.*]] = icmp eq <2 x i8> [[AND]], [[X]] ; CHECK-NEXT: ret <2 x i1> [[Z]] ; %and = and <2 x i8> %x, %y @@ -43,7 +43,7 @@ ; CHECK-LABEL: @icmp_uge_x_y_2( ; CHECK-NEXT: [[X:%.*]] = mul i8 [[XX:%.*]], [[XX]] ; CHECK-NEXT: [[AND:%.*]] = and i8 [[X]], [[Y:%.*]] -; CHECK-NEXT: [[Z:%.*]] = icmp ule i8 [[X]], [[AND]] +; CHECK-NEXT: [[Z:%.*]] = icmp eq i8 [[AND]], [[X]] ; CHECK-NEXT: ret i1 [[Z]] ; %x = mul i8 %xx, %xx