Index: llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp =================================================================== --- llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp +++ llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp @@ -2524,6 +2524,34 @@ } } + // sext(X + Y) - sext(X + Z) -> sext(Y) - sext(Z) + if ((match(Op0, m_SExt(m_NSWAdd(m_Value(X), m_Value(Y)))) && + match(Op1, m_SExt(m_c_Add(m_Specific(X), m_Value(Z))))) || + (match(Op0, m_SExt(m_NSWAdd(m_Value(Y), m_Value(X)))) && + match(Op1, m_SExt(m_c_Add(m_Specific(X), m_Value(Z)))))) { + Value *Add1 = cast(Op1)->getOperand(0); + if ((Op0->hasOneUse() || Op1->hasOneUse() || + (isa(Y) && isa(Z))) && + cast(Add1)->hasNoSignedWrap()) { + Value *S1 = Builder.CreateSExt(Y, Ty); + Value *S2 = Builder.CreateSExt(Z, Ty); + return BinaryOperator::CreateSub(S1, S2); + } + } + if ((match(Op0, m_ZExt(m_NUWAdd(m_Value(X), m_Value(Y)))) && + match(Op1, m_ZExt(m_c_Add(m_Specific(X), m_Value(Z))))) || + (match(Op0, m_ZExt(m_NUWAdd(m_Value(Y), m_Value(X)))) && + match(Op1, m_ZExt(m_c_Add(m_Specific(X), m_Value(Z)))))) { + Value *Add1 = cast(Op1)->getOperand(0); + if ((Op0->hasOneUse() || Op1->hasOneUse() || + (isa(Y) && isa(Z))) && + cast(Add1)->hasNoUnsignedWrap()) { + Value *S1 = Builder.CreateZExt(Y, Ty); + Value *S2 = Builder.CreateZExt(Z, Ty); + return BinaryOperator::CreateSub(S1, S2); + } + } + if (Instruction *Res = foldBinOpOfSelectAndCastOfSelectCondition(I)) return Res; Index: llvm/test/Transforms/InstCombine/sub-ext-add.ll =================================================================== --- llvm/test/Transforms/InstCombine/sub-ext-add.ll +++ llvm/test/Transforms/InstCombine/sub-ext-add.ll @@ -3,11 +3,9 @@ define i32 @subaddnuw(i8 %a, i8 %C1, i8 %C2) { ; CHECK-LABEL: @subaddnuw( -; CHECK-NEXT: [[A1:%.*]] = add nuw i8 [[A:%.*]], [[C1:%.*]] -; CHECK-NEXT: [[Z1:%.*]] = zext i8 [[A1]] to i32 -; CHECK-NEXT: [[A2:%.*]] = add nuw i8 [[A]], [[C2:%.*]] -; CHECK-NEXT: [[Z2:%.*]] = zext i8 [[A2]] to i32 -; CHECK-NEXT: [[S:%.*]] = sub nsw i32 [[Z2]], [[Z1]] +; CHECK-NEXT: [[TMP1:%.*]] = zext i8 [[C2:%.*]] to i32 +; CHECK-NEXT: [[TMP2:%.*]] = zext i8 [[C1:%.*]] to i32 +; CHECK-NEXT: [[S:%.*]] = sub nsw i32 [[TMP1]], [[TMP2]] ; CHECK-NEXT: ret i32 [[S]] ; %a1 = add nuw i8 %a, %C1 @@ -20,11 +18,9 @@ define i32 @subaddnuw_c1(i8 %a, i8 %C1, i8 %C2) { ; CHECK-LABEL: @subaddnuw_c1( -; CHECK-NEXT: [[A1:%.*]] = add nuw i8 [[C1:%.*]], [[A:%.*]] -; CHECK-NEXT: [[Z1:%.*]] = zext i8 [[A1]] to i32 -; CHECK-NEXT: [[A2:%.*]] = add nuw i8 [[A]], [[C2:%.*]] -; CHECK-NEXT: [[Z2:%.*]] = zext i8 [[A2]] to i32 -; CHECK-NEXT: [[S:%.*]] = sub nsw i32 [[Z2]], [[Z1]] +; CHECK-NEXT: [[TMP1:%.*]] = zext i8 [[C2:%.*]] to i32 +; CHECK-NEXT: [[TMP2:%.*]] = zext i8 [[C1:%.*]] to i32 +; CHECK-NEXT: [[S:%.*]] = sub nsw i32 [[TMP1]], [[TMP2]] ; CHECK-NEXT: ret i32 [[S]] ; %a1 = add nuw i8 %C1, %a @@ -37,11 +33,9 @@ define i32 @subaddnuw_c2(i8 %a, i8 %C1, i8 %C2) { ; CHECK-LABEL: @subaddnuw_c2( -; CHECK-NEXT: [[A1:%.*]] = add nuw i8 [[C1:%.*]], [[A:%.*]] -; CHECK-NEXT: [[Z1:%.*]] = zext i8 [[A1]] to i32 -; CHECK-NEXT: [[A2:%.*]] = add nuw i8 [[C2:%.*]], [[A]] -; CHECK-NEXT: [[Z2:%.*]] = zext i8 [[A2]] to i32 -; CHECK-NEXT: [[S:%.*]] = sub nsw i32 [[Z2]], [[Z1]] +; CHECK-NEXT: [[TMP1:%.*]] = zext i8 [[C2:%.*]] to i32 +; CHECK-NEXT: [[TMP2:%.*]] = zext i8 [[C1:%.*]] to i32 +; CHECK-NEXT: [[S:%.*]] = sub nsw i32 [[TMP1]], [[TMP2]] ; CHECK-NEXT: ret i32 [[S]] ; %a1 = add nuw i8 %C1, %a @@ -54,11 +48,9 @@ define i32 @subaddnuw_c3(i8 %a, i8 %C1, i8 %C2) { ; CHECK-LABEL: @subaddnuw_c3( -; CHECK-NEXT: [[A1:%.*]] = add nuw i8 [[C1:%.*]], [[A:%.*]] -; CHECK-NEXT: [[Z1:%.*]] = zext i8 [[A1]] to i32 -; CHECK-NEXT: [[A2:%.*]] = add nuw i8 [[A]], [[C2:%.*]] -; CHECK-NEXT: [[Z2:%.*]] = zext i8 [[A2]] to i32 -; CHECK-NEXT: [[S:%.*]] = sub nsw i32 [[Z2]], [[Z1]] +; CHECK-NEXT: [[TMP1:%.*]] = zext i8 [[C2:%.*]] to i32 +; CHECK-NEXT: [[TMP2:%.*]] = zext i8 [[C1:%.*]] to i32 +; CHECK-NEXT: [[S:%.*]] = sub nsw i32 [[TMP1]], [[TMP2]] ; CHECK-NEXT: ret i32 [[S]] ; %a1 = add nuw i8 %C1, %a @@ -71,12 +63,7 @@ define i32 @subaddnuw_const(i8 %a) { ; CHECK-LABEL: @subaddnuw_const( -; CHECK-NEXT: [[A1:%.*]] = add nuw i8 [[A:%.*]], 1 -; CHECK-NEXT: [[Z1:%.*]] = zext i8 [[A1]] to i32 -; CHECK-NEXT: [[A2:%.*]] = add nuw i8 [[A]], 2 -; CHECK-NEXT: [[Z2:%.*]] = zext i8 [[A2]] to i32 -; CHECK-NEXT: [[S:%.*]] = sub nsw i32 [[Z2]], [[Z1]] -; CHECK-NEXT: ret i32 [[S]] +; CHECK-NEXT: ret i32 1 ; %a1 = add nuw i8 %a, 1 %z1 = zext i8 %a1 to i32 @@ -88,11 +75,9 @@ define i32 @subaddnsw(i8 %a, i8 %C1, i8 %C2) { ; CHECK-LABEL: @subaddnsw( -; CHECK-NEXT: [[A1:%.*]] = add nsw i8 [[A:%.*]], [[C1:%.*]] -; CHECK-NEXT: [[Z1:%.*]] = sext i8 [[A1]] to i32 -; CHECK-NEXT: [[A2:%.*]] = add nsw i8 [[A]], [[C2:%.*]] -; CHECK-NEXT: [[Z2:%.*]] = sext i8 [[A2]] to i32 -; CHECK-NEXT: [[S:%.*]] = sub nsw i32 [[Z2]], [[Z1]] +; CHECK-NEXT: [[TMP1:%.*]] = sext i8 [[C2:%.*]] to i32 +; CHECK-NEXT: [[TMP2:%.*]] = sext i8 [[C1:%.*]] to i32 +; CHECK-NEXT: [[S:%.*]] = sub nsw i32 [[TMP1]], [[TMP2]] ; CHECK-NEXT: ret i32 [[S]] ; %a1 = add nsw i8 %a, %C1 @@ -105,12 +90,7 @@ define i32 @subaddnsw_c(i8 %a) { ; CHECK-LABEL: @subaddnsw_c( -; CHECK-NEXT: [[A1:%.*]] = add nsw i8 [[A:%.*]], 1 -; CHECK-NEXT: [[Z1:%.*]] = sext i8 [[A1]] to i32 -; CHECK-NEXT: [[A2:%.*]] = add nsw i8 [[A]], 2 -; CHECK-NEXT: [[Z2:%.*]] = sext i8 [[A2]] to i32 -; CHECK-NEXT: [[S:%.*]] = sub nsw i32 [[Z2]], [[Z1]] -; CHECK-NEXT: ret i32 [[S]] +; CHECK-NEXT: ret i32 1 ; %a1 = add nsw i8 %a, 1 %z1 = sext i8 %a1 to i32 @@ -157,10 +137,9 @@ define i32 @subaddnuw_useadd(i8 %a, i8 %C1, i8 %C2) { ; CHECK-LABEL: @subaddnuw_useadd( ; CHECK-NEXT: [[A1:%.*]] = add nuw i8 [[A:%.*]], [[C1:%.*]] -; CHECK-NEXT: [[Z1:%.*]] = zext i8 [[A1]] to i32 -; CHECK-NEXT: [[A2:%.*]] = add nuw i8 [[A]], [[C2:%.*]] -; CHECK-NEXT: [[Z2:%.*]] = zext i8 [[A2]] to i32 -; CHECK-NEXT: [[S:%.*]] = sub nsw i32 [[Z2]], [[Z1]] +; CHECK-NEXT: [[TMP1:%.*]] = zext i8 [[C2:%.*]] to i32 +; CHECK-NEXT: [[TMP2:%.*]] = zext i8 [[C1]] to i32 +; CHECK-NEXT: [[S:%.*]] = sub nsw i32 [[TMP1]], [[TMP2]] ; CHECK-NEXT: call void @use8(i8 [[A1]]) ; CHECK-NEXT: ret i32 [[S]] ; @@ -177,9 +156,9 @@ ; CHECK-LABEL: @subaddnuw_usezext( ; CHECK-NEXT: [[A1:%.*]] = add nuw i8 [[A:%.*]], [[C1:%.*]] ; CHECK-NEXT: [[Z1:%.*]] = zext i8 [[A1]] to i32 -; CHECK-NEXT: [[A2:%.*]] = add nuw i8 [[A]], [[C2:%.*]] -; CHECK-NEXT: [[Z2:%.*]] = zext i8 [[A2]] to i32 -; CHECK-NEXT: [[S:%.*]] = sub nsw i32 [[Z2]], [[Z1]] +; CHECK-NEXT: [[TMP1:%.*]] = zext i8 [[C2:%.*]] to i32 +; CHECK-NEXT: [[TMP2:%.*]] = zext i8 [[C1]] to i32 +; CHECK-NEXT: [[S:%.*]] = sub nsw i32 [[TMP1]], [[TMP2]] ; CHECK-NEXT: call void @use32(i32 [[Z1]]) ; CHECK-NEXT: ret i32 [[S]] ; @@ -195,10 +174,10 @@ define i32 @subaddnuw_twouseadd(i8 %a, i8 %C1, i8 %C2) { ; CHECK-LABEL: @subaddnuw_twouseadd( ; CHECK-NEXT: [[A1:%.*]] = add nuw i8 [[A:%.*]], [[C1:%.*]] -; CHECK-NEXT: [[Z1:%.*]] = zext i8 [[A1]] to i32 ; CHECK-NEXT: [[A2:%.*]] = add nuw i8 [[A]], [[C2:%.*]] -; CHECK-NEXT: [[Z2:%.*]] = zext i8 [[A2]] to i32 -; CHECK-NEXT: [[S:%.*]] = sub nsw i32 [[Z2]], [[Z1]] +; CHECK-NEXT: [[TMP1:%.*]] = zext i8 [[C2]] to i32 +; CHECK-NEXT: [[TMP2:%.*]] = zext i8 [[C1]] to i32 +; CHECK-NEXT: [[S:%.*]] = sub nsw i32 [[TMP1]], [[TMP2]] ; CHECK-NEXT: call void @use8(i8 [[A1]]) ; CHECK-NEXT: call void @use8(i8 [[A2]]) ; CHECK-NEXT: ret i32 [[S]] @@ -240,10 +219,9 @@ ; CHECK-NEXT: [[Z1:%.*]] = zext i8 [[A1]] to i32 ; CHECK-NEXT: [[A2:%.*]] = add nuw i8 [[A]], 2 ; CHECK-NEXT: [[Z2:%.*]] = zext i8 [[A2]] to i32 -; CHECK-NEXT: [[S:%.*]] = sub nsw i32 [[Z2]], [[Z1]] ; CHECK-NEXT: call void @use32(i32 [[Z1]]) ; CHECK-NEXT: call void @use32(i32 [[Z2]]) -; CHECK-NEXT: ret i32 [[S]] +; CHECK-NEXT: ret i32 1 ; %a1 = add nuw i8 %a, 1 %z1 = zext i8 %a1 to i32