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 @@ -4430,6 +4430,30 @@ return nullptr; } +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; @@ -4959,6 +4983,9 @@ if (Value *V = foldICmpWithLowBitMaskedVal(I, Builder)) return replaceInstUsesWith(I, V); + if (Instruction *R = foldICmpAndXX(I, Q, *this)) + return R; + if (Value *V = foldICmpWithTruncSignExtendedVal(I, Builder)) return replaceInstUsesWith(I, V); 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 @@ -62,8 +62,8 @@ 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: [[TMP1:%.*]] = and <2 x i8> [[X:%.*]], +; CHECK-NEXT: [[RET:%.*]] = icmp eq <2 x i8> [[TMP1]], zeroinitializer ; CHECK-NEXT: ret <2 x i1> [[RET]] ; %tmp0 = and <2 x i8> %x, @@ -175,8 +175,8 @@ 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: [[TMP1:%.*]] = and i8 [[X:%.*]], -5 +; CHECK-NEXT: [[RET:%.*]] = icmp eq i8 [[TMP1]], 0 ; CHECK-NEXT: ret i1 [[RET]] ; %tmp0 = and i8 %x, 4 ; power-of-two, but invalid. @@ -197,8 +197,8 @@ 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: [[TMP1:%.*]] = and <2 x i8> [[X:%.*]], +; CHECK-NEXT: [[RET:%.*]] = icmp eq <2 x i8> [[TMP1]], zeroinitializer ; 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 @@ -75,8 +75,8 @@ define <2 x i1> @p2_vec_nonsplat_edgecase0() { ; 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: [[TMP1:%.*]] = and <2 x i8> [[X]], +; CHECK-NEXT: [[RET:%.*]] = icmp ne <2 x i8> [[TMP1]], zeroinitializer ; CHECK-NEXT: ret <2 x i1> [[RET]] ; %x = call <2 x i8> @gen2x8() @@ -201,8 +201,8 @@ define i1 @n0() { ; 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: [[TMP1:%.*]] = and i8 [[X]], -5 +; CHECK-NEXT: [[RET:%.*]] = icmp ne i8 [[TMP1]], 0 ; CHECK-NEXT: ret i1 [[RET]] ; %x = call i8 @gen8() @@ -227,8 +227,8 @@ define <2 x i1> @n2() { ; 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: [[TMP1:%.*]] = and <2 x i8> [[X]], +; CHECK-NEXT: [[RET:%.*]] = icmp ne <2 x i8> [[TMP1]], zeroinitializer ; 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 @@ -75,8 +75,8 @@ define <2 x i1> @p2_vec_nonsplat_edgecase0() { ; 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: [[TMP1:%.*]] = and <2 x i8> [[X]], +; CHECK-NEXT: [[RET:%.*]] = icmp eq <2 x i8> [[TMP1]], zeroinitializer ; CHECK-NEXT: ret <2 x i1> [[RET]] ; %x = call <2 x i8> @gen2x8() @@ -189,8 +189,8 @@ define i1 @n0() { ; 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: [[TMP1:%.*]] = and i8 [[X]], -5 +; CHECK-NEXT: [[RET:%.*]] = icmp eq i8 [[TMP1]], 0 ; CHECK-NEXT: ret i1 [[RET]] ; %x = call i8 @gen8() @@ -215,8 +215,8 @@ define <2 x i1> @n2() { ; 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: [[TMP1:%.*]] = and <2 x i8> [[X]], +; CHECK-NEXT: [[RET:%.*]] = icmp eq <2 x i8> [[TMP1]], zeroinitializer ; 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 @@ -62,8 +62,8 @@ 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: [[TMP1:%.*]] = and <2 x i8> [[X:%.*]], +; CHECK-NEXT: [[RET:%.*]] = icmp ne <2 x i8> [[TMP1]], zeroinitializer ; CHECK-NEXT: ret <2 x i1> [[RET]] ; %tmp0 = and <2 x i8> %x, @@ -186,8 +186,8 @@ 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: [[TMP1:%.*]] = and i8 [[X:%.*]], -5 +; CHECK-NEXT: [[RET:%.*]] = icmp ne i8 [[TMP1]], 0 ; CHECK-NEXT: ret i1 [[RET]] ; %tmp0 = and i8 %x, 4 ; power-of-two, but invalid. @@ -208,8 +208,8 @@ 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: [[TMP1:%.*]] = and <2 x i8> [[X:%.*]], +; CHECK-NEXT: [[RET:%.*]] = icmp ne <2 x i8> [[TMP1]], zeroinitializer ; 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