Index: llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp =================================================================== --- llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp +++ llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp @@ -1987,6 +1987,20 @@ // C-(C2-X) --> X+(C-C2) if (match(Op1, m_Sub(m_ImmConstant(C2), m_Value(X)))) return BinaryOperator::CreateAdd(X, ConstantExpr::getSub(C, C2)); + + // C - ((C3 -nuw X) & C2) --> X & C2 when: + // ((C2 & C3) == C) && (C3 - C + 1) is Pow2. + Constant *C3; + if (match(Op1, m_And(m_NUWSub(m_ImmConstant(C3), m_Value(X)), + m_ImmConstant(C2)))) { + Constant *C2AndC3 = ConstantExpr::getAnd(C2, C3); + Constant *Cond = + ConstantExpr::getICmp(ICmpInst::ICMP_NE, C, C2AndC3, true); + Constant *C3SubC = ConstantExpr::getSub(C3, C); + if (Cond && match(Cond, m_Zero()) && + match(InstCombiner::AddOne(C3SubC), m_Power2())) + return BinaryOperator::CreateAnd(X, C2); + } } const APInt *Op0C; Index: llvm/test/Transforms/InstCombine/sub.ll =================================================================== --- llvm/test/Transforms/InstCombine/sub.ll +++ llvm/test/Transforms/InstCombine/sub.ll @@ -2119,3 +2119,104 @@ %r = shl i8 %s, 2 ret i8 %r } + +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 != c1 +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 - c1 + 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 +} + +; no nuw +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]], -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 <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: [[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 +}