Index: llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp =================================================================== --- llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp +++ llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp @@ -1990,12 +1990,28 @@ } const APInt *Op0C; - if (match(Op0, m_APInt(Op0C)) && Op0C->isMask()) { - // Turn this into a xor if LHS is 2^n-1 and the remaining bits are known - // zero. - KnownBits RHSKnown = computeKnownBits(Op1, 0, &I); - if ((*Op0C | RHSKnown.Zero).isAllOnes()) - return BinaryOperator::CreateXor(Op1, Op0); + if (match(Op0, m_APInt(Op0C))) { + if (Op0C->isMask()) { + // Turn this into a xor if LHS is 2^n-1 and the remaining bits are known + // zero. + KnownBits RHSKnown = computeKnownBits(Op1, 0, &I); + if ((*Op0C | RHSKnown.Zero).isAllOnes()) + return BinaryOperator::CreateXor(Op1, Op0); + } + + // C - ((C3 -nuw X) & C2) --> X & C2 when: + // (C2 & C3) == C && + // (C3 - (C - 1)) is pow2 && + // ((C2 + C3) & (C - 1)) == (C - 1) + const APInt *C2, *C3; + if (match(Op1, m_And(m_NUWSub(m_APInt(C3), m_Value(X)), m_APInt(C2)))) { + APInt C2AndC3 = *C2 & *C3; + APInt CMinus1 = *Op0C - 1; + APInt C2AddC3 = *C2 + *C3; + if (C2AndC3 == *Op0C && (*C3 - CMinus1).isPowerOf2() && + CMinus1.isSubsetOf(C2AddC3)) + return BinaryOperator::CreateAnd(X, ConstantInt::get(I.getType(), *C2)); + } } { Index: llvm/test/Transforms/InstCombine/sub.ll =================================================================== --- llvm/test/Transforms/InstCombine/sub.ll +++ llvm/test/Transforms/InstCombine/sub.ll @@ -2119,3 +2119,128 @@ %r = shl i8 %s, 2 ret i8 %r } + +; C - ((C3 -nuw X) & C2) --> X & C2 when: +; (C2 & C3) == C && +; (C3 - (C - 1)) is pow2 && +; ((C2 + C3) & (C - 1)) == (C - 1) +define i10 @sub_to_and(i10 %x) { +; CHECK-LABEL: @sub_to_and( +; CHECK-NEXT: [[R:%.*]] = and i10 [[X:%.*]], -8 +; CHECK-NEXT: ret i10 [[R]] +; + %sub = sub nuw i10 71, %x + %and = and i10 %sub, -8 + %r = sub i10 64, %and + ret i10 %r +} + +; (C2 & C3) != C +define i10 @sub_to_and_negative1(i10 %x) { +; CHECK-LABEL: @sub_to_and_negative1( +; CHECK-NEXT: [[SUB:%.*]] = sub i10 7, [[X:%.*]] +; CHECK-NEXT: [[AND:%.*]] = and i10 [[SUB]], 34 +; CHECK-NEXT: [[R:%.*]] = sub nuw nsw i10 64, [[AND]] +; CHECK-NEXT: ret i10 [[R]] +; + %sub = sub nuw i10 71, %x + %and = and i10 %sub, 34 + %r = sub i10 64, %and + ret i10 %r +} + +; (C3 - (C - 1)) is not pow2 +define i10 @sub_to_and_negative2(i10 %x) { +; CHECK-LABEL: @sub_to_and_negative2( +; CHECK-NEXT: [[SUB:%.*]] = sub i10 71, [[X:%.*]] +; CHECK-NEXT: [[AND:%.*]] = and i10 [[SUB]], 248 +; CHECK-NEXT: [[R:%.*]] = sub nsw i10 64, [[AND]] +; CHECK-NEXT: ret i10 [[R]] +; + %sub = sub nuw i10 327, %x + %and = and i10 %sub, 248 + %r = sub i10 64, %and + ret i10 %r +} + +; ((C2 + C3) & (C - 1)) != (C - 1) +define i10 @sub_to_and_negative3(i10 %x) { +; CHECK-LABEL: @sub_to_and_negative3( +; CHECK-NEXT: [[SUB:%.*]] = sub nuw i10 71, [[X:%.*]] +; CHECK-NEXT: [[AND:%.*]] = and i10 [[SUB]], 88 +; CHECK-NEXT: [[R:%.*]] = sub nsw i10 64, [[AND]] +; CHECK-NEXT: ret i10 [[R]] +; + %sub = sub nuw i10 71, %x + %and = and i10 %sub, 88 + %r = sub i10 64, %and + ret i10 %r +} + +; no nuw +define i10 @sub_to_and_negative4(i10 %x) { +; CHECK-LABEL: @sub_to_and_negative4( +; CHECK-NEXT: [[SUB:%.*]] = sub i10 71, [[X:%.*]] +; CHECK-NEXT: [[AND:%.*]] = and i10 [[SUB]], -8 +; CHECK-NEXT: [[R:%.*]] = sub i10 64, [[AND]] +; CHECK-NEXT: ret i10 [[R]] +; + %sub = sub i10 71, %x + %and = and i10 %sub, -8 + %r = sub i10 64, %and + ret i10 %r +} + + +define <2 x i8> @sub_to_and_vector1(<2 x i8> %x) { +; CHECK-LABEL: @sub_to_and_vector1( +; CHECK-NEXT: [[R:%.*]] = and <2 x i8> [[X:%.*]], +; CHECK-NEXT: ret <2 x i8> [[R]] +; + %sub = sub nuw <2 x i8> , %x + %and = and <2 x i8> %sub, + %r = sub <2 x i8> , %and + ret <2 x i8> %r +} + + +define <2 x i8> @sub_to_and_vector2(<2 x i8> %x) { +; CHECK-LABEL: @sub_to_and_vector2( +; CHECK-NEXT: [[SUB:%.*]] = sub nuw <2 x i8> , [[X:%.*]] +; CHECK-NEXT: [[AND:%.*]] = and <2 x i8> [[SUB]], +; CHECK-NEXT: [[R:%.*]] = sub nsw <2 x i8> , [[AND]] +; CHECK-NEXT: ret <2 x i8> [[R]] +; + %sub = sub nuw <2 x i8> , %x + %and = and <2 x i8> %sub, + %r = sub <2 x i8> , %and + ret <2 x i8> %r +} + + +define <2 x i8> @sub_to_and_vector3(<2 x i8> %x) { +; CHECK-LABEL: @sub_to_and_vector3( +; CHECK-NEXT: [[SUB:%.*]] = sub nuw <2 x i8> , [[X:%.*]] +; CHECK-NEXT: [[AND:%.*]] = and <2 x i8> [[SUB]], +; CHECK-NEXT: [[R:%.*]] = sub <2 x i8> , [[AND]] +; CHECK-NEXT: ret <2 x i8> [[R]] +; + %sub = sub nuw <2 x i8> , %x + %and = and <2 x i8> %sub, + %r = sub <2 x i8> , %and + ret <2 x i8> %r +} + + +define <2 x i8> @sub_to_and_vector4(<2 x i8> %x) { +; CHECK-LABEL: @sub_to_and_vector4( +; CHECK-NEXT: [[SUB:%.*]] = sub nuw <2 x i8> , [[X:%.*]] +; CHECK-NEXT: [[AND:%.*]] = and <2 x i8> [[SUB]], +; CHECK-NEXT: [[R:%.*]] = sub <2 x i8> , [[AND]] +; CHECK-NEXT: ret <2 x i8> [[R]] +; + %sub = sub nuw <2 x i8> , %x + %and = and <2 x i8> %sub, + %r = sub <2 x i8> , %and + ret <2 x i8> %r +}