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 @@ -1415,6 +1415,15 @@ return BinaryOperator::CreateAnd(A, NewMask); } + // ZExt (B - A) + ZExt(A) --> ZExt(B) + if ((match(RHS, m_ZExt(m_Value(A))) && + match(LHS, m_ZExt(m_NUWSub(m_Value(B), m_Specific(A))))) || + (match(LHS, m_ZExt(m_Value(A))) && + match(RHS, m_ZExt(m_NUWSub(m_Value(B), m_Specific(A)))))) { + Value *Res = Builder.CreateZExt(B, LHS->getType()); + return replaceInstUsesWith(I, Res); + } + // A+B --> A|B iff A and B have no bits set in common. if (haveNoCommonBitsSet(LHS, RHS, DL, &AC, &I, &DT)) return BinaryOperator::CreateOr(LHS, RHS); diff --git a/llvm/test/Transforms/InstCombine/add.ll b/llvm/test/Transforms/InstCombine/add.ll --- a/llvm/test/Transforms/InstCombine/add.ll +++ b/llvm/test/Transforms/InstCombine/add.ll @@ -2335,6 +2335,56 @@ ret i8 %a } +define i16 @add_sub_zext_1(i8 %x, i8 %y) { +; CHECK-LABEL: @add_sub_zext_1( +; CHECK-NEXT: [[TMP1:%.*]] = zext i8 [[Y:%.*]] to i16 +; CHECK-NEXT: ret i16 [[TMP1]] +; + %1 = sub nuw i8 %y, %x + %2 = zext i8 %1 to i16 + %3 = zext i8 %x to i16 + %4 = add i16 %2, %3 + ret i16 %4 +} + +define i16 @add_sub_zext_2(i8 %x, i8 %y) { +; CHECK-LABEL: @add_sub_zext_2( +; CHECK-NEXT: [[TMP1:%.*]] = zext i8 [[Y:%.*]] to i16 +; CHECK-NEXT: ret i16 [[TMP1]] +; + %1 = sub nuw i8 %y, %x + %2 = zext i8 %1 to i16 + %3 = zext i8 %x to i16 + %4 = add i16 %3, %2 + ret i16 %4 +} + +define i16 @add_no_nuw_sub_zext(i8 %x, i8 %y) { +; CHECK-LABEL: @add_no_nuw_sub_zext( +; CHECK-NEXT: [[TMP1:%.*]] = sub i8 [[Y:%.*]], [[X:%.*]] +; CHECK-NEXT: [[TMP2:%.*]] = zext i8 [[TMP1]] to i16 +; CHECK-NEXT: [[TMP3:%.*]] = zext i8 [[X]] to i16 +; CHECK-NEXT: [[TMP4:%.*]] = add nuw nsw i16 [[TMP3]], [[TMP2]] +; CHECK-NEXT: ret i16 [[TMP4]] +; + %1 = sub i8 %y, %x + %2 = zext i8 %1 to i16 + %3 = zext i8 %x to i16 + %4 = add i16 %3, %2 + ret i16 %4 +} + +define i16 @add_sub_zext_constant(i8 %x) { +; CHECK-LABEL: @add_sub_zext_constant( +; CHECK-NEXT: ret i16 254 +; + %1 = sub nuw i8 254, %x + %2 = zext i8 %1 to i16 + %3 = zext i8 %x to i16 + %4 = add i16 %2, %3 + ret i16 %4 +} + define @add_to_or_scalable( %in) { ; CHECK-LABEL: @add_to_or_scalable( ; CHECK-NEXT: [[SHL:%.*]] = shl [[IN:%.*]], shufflevector ( insertelement ( poison, i32 1, i32 0), poison, zeroinitializer)