diff --git a/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp --- a/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp @@ -2032,12 +2032,34 @@ } 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) --> (C - (C2 & C3)) + (X & C2) when: + // (C3 - ((C2 & C3) - 1)) is pow2 + // ((C2 + C3) & ((C2 & C3) - 1)) == ((C2 & C3) - 1) + // C2 is negative pow2 || sub nuw + const APInt *C2, *C3; + BinaryOperator *InnerSub; + if (match(Op1, m_OneUse(m_And(m_BinOp(InnerSub), m_APInt(C2)))) && + match(InnerSub, m_Sub(m_APInt(C3), m_Value(X))) && + (InnerSub->hasNoUnsignedWrap() || C2->isNegatedPowerOf2())) { + APInt C2AndC3 = *C2 & *C3; + APInt C2AndC3Minus1 = C2AndC3 - 1; + APInt C2AddC3 = *C2 + *C3; + if ((*C3 - C2AndC3Minus1).isPowerOf2() && + C2AndC3Minus1.isSubsetOf(C2AddC3)) { + Value *And = Builder.CreateAnd(X, ConstantInt::get(I.getType(), *C2)); + return BinaryOperator::CreateAdd( + And, ConstantInt::get(I.getType(), *Op0C - C2AndC3)); + } + } } { diff --git a/llvm/test/Transforms/InstCombine/sub.ll b/llvm/test/Transforms/InstCombine/sub.ll --- a/llvm/test/Transforms/InstCombine/sub.ll +++ b/llvm/test/Transforms/InstCombine/sub.ll @@ -2229,16 +2229,14 @@ ret i8 %r } -; TODO: ; C - ((C3 - X) & C2) --> (C - (C2 & C3)) + (X & C2) when: -; (C3 - (C2 & C3) + 1) is pow2 +; (C3 - ((C2 & C3) - 1)) is pow2 ; ((C2 + C3) & ((C2 & C3) - 1)) == ((C2 & C3) - 1) ; C2 is negative pow2 define i10 @sub_to_and_nuw(i10 %x) { ; CHECK-LABEL: @sub_to_and_nuw( -; CHECK-NEXT: [[SUB:%.*]] = sub nuw i10 71, [[X:%.*]] -; CHECK-NEXT: [[AND:%.*]] = and i10 [[SUB]], 120 -; CHECK-NEXT: [[R:%.*]] = sub nuw nsw i10 443, [[AND]] +; CHECK-NEXT: [[TMP1:%.*]] = and i10 [[X:%.*]], 120 +; CHECK-NEXT: [[R:%.*]] = add nuw nsw i10 [[TMP1]], 379 ; CHECK-NEXT: ret i10 [[R]] ; %sub = sub nuw i10 71, %x @@ -2247,15 +2245,13 @@ ret i10 %r } -; TODO: ; C - ((C3 -nuw X) & C2) --> (C - (C2 & C3)) + (X & C2) when: -; (C3 - (C2 & C3) + 1) is pow2 +; (C3 - ((C2 & C3) - 1)) is pow2 ; ((C2 + C3) & ((C2 & C3) - 1)) == ((C2 & C3) - 1) define i10 @sub_to_and_negpow2(i10 %x) { ; CHECK-LABEL: @sub_to_and_negpow2( -; CHECK-NEXT: [[SUB:%.*]] = sub i10 71, [[X:%.*]] -; CHECK-NEXT: [[AND:%.*]] = and i10 [[SUB]], -8 -; CHECK-NEXT: [[R:%.*]] = sub i10 33, [[AND]] +; CHECK-NEXT: [[TMP1:%.*]] = and i10 [[X:%.*]], -8 +; CHECK-NEXT: [[R:%.*]] = add i10 [[TMP1]], -31 ; CHECK-NEXT: ret i10 [[R]] ; %sub = sub i10 71, %x @@ -2342,9 +2338,8 @@ define <2 x i8> @sub_to_and_vector1(<2 x i8> %x) { ; CHECK-LABEL: @sub_to_and_vector1( -; 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: [[TMP1:%.*]] = and <2 x i8> [[X:%.*]], +; CHECK-NEXT: [[R:%.*]] = add nsw <2 x i8> [[TMP1]], ; CHECK-NEXT: ret <2 x i8> [[R]] ; %sub = sub nuw <2 x i8> , %x