Index: llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp =================================================================== --- llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp +++ 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)))) { + APInt C2AndC3 = *C2 & *C3; + APInt C2AndC3Minus1 = C2AndC3 - 1; + APInt C2AddC3 = *C2 + *C3; + if ((InnerSub->hasNoUnsignedWrap() || C2->isNegatedPowerOf2()) && + (*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)); + } + } } { Index: llvm/test/Transforms/InstCombine/sub.ll =================================================================== --- llvm/test/Transforms/InstCombine/sub.ll +++ llvm/test/Transforms/InstCombine/sub.ll @@ -2228,3 +2228,162 @@ %r = lshr i8 %sub, 4 ; 4 low bits are not demanded ret i8 %r } + + +; 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 +define i10 @sub_to_and_nuw(i10 %x) { +; CHECK-LABEL: @sub_to_and_nuw( +; 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 + %and = and i10 %sub, 120 + %r = sub i10 443, %and + ret i10 %r +} + +define i10 @sub_to_and_negpow2(i10 %x) { +; CHECK-LABEL: @sub_to_and_negpow2( +; CHECK-NEXT: [[TMP1:%.*]] = and i10 [[X:%.*]], -8 +; CHECK-NEXT: [[R:%.*]] = add i10 [[TMP1]], -31 +; CHECK-NEXT: ret i10 [[R]] +; + %sub = sub i10 71, %x + %and = and i10 %sub, -8 + %r = sub i10 33, %and + ret i10 %r +} + +; TODO: +; C + ((C3 -nuw X) & C2) --> (C + (C2 & C3)) - (X & C2) when: +define i10 @add_to_and_nuw(i10 %x) { +; CHECK-LABEL: @add_to_and_nuw( +; CHECK-NEXT: [[SUB:%.*]] = sub nuw i10 71, [[X:%.*]] +; CHECK-NEXT: [[AND:%.*]] = and i10 [[SUB]], 120 +; CHECK-NEXT: [[R:%.*]] = add nuw nsw i10 [[AND]], 224 +; CHECK-NEXT: ret i10 [[R]] +; + %sub = sub nuw i10 71, %x + %and = and i10 %sub, 120 + %r = add i10 224, %and + ret i10 %r +} + +; (C3 - (C2 & C3) + 1) is not pow2 +define i10 @sub_to_and_negative1(i10 %x) { +; CHECK-LABEL: @sub_to_and_negative1( +; CHECK-NEXT: [[SUB:%.*]] = sub i10 71, [[X:%.*]] +; CHECK-NEXT: [[AND:%.*]] = and i10 [[SUB]], 248 +; CHECK-NEXT: [[R:%.*]] = sub nuw nsw i10 444, [[AND]] +; CHECK-NEXT: ret i10 [[R]] +; + %sub = sub nuw i10 327, %x + %and = and i10 %sub, 248 + %r = sub i10 444, %and + ret i10 %r +} + +; ((C2 + C3) & ((C2 & C3) - 1)) == ((C2 & C3) - 1) +define i10 @sub_to_and_negative2(i10 %x) { +; CHECK-LABEL: @sub_to_and_negative2( +; 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 && C2 is not neg-pow2 +define i10 @sub_to_and_negative3(i10 %x) { +; CHECK-LABEL: @sub_to_and_negative3( +; CHECK-NEXT: [[SUB:%.*]] = sub i10 71, [[X:%.*]] +; CHECK-NEXT: [[AND:%.*]] = and i10 [[SUB]], 120 +; CHECK-NEXT: [[R:%.*]] = sub nsw i10 64, [[AND]] +; CHECK-NEXT: ret i10 [[R]] +; + %sub = sub i10 71, %x + %and = and i10 %sub, 120 + %r = sub i10 64, %and + ret i10 %r +} + +declare void @use10(i10) + +; and is not one-use +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]], 120 +; CHECK-NEXT: [[R:%.*]] = sub nsw i10 64, [[AND]] +; CHECK-NEXT: call void @use10(i10 [[AND]]) +; CHECK-NEXT: ret i10 [[R]] +; + %sub = sub i10 71, %x + %and = and i10 %sub, 120 + %r = sub i10 64, %and + call void @use10(i10 %and) + ret i10 %r +} + + +define <2 x i8> @sub_to_and_vector1(<2 x i8> %x) { +; CHECK-LABEL: @sub_to_and_vector1( +; 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 + %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 +}