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 @@ -2008,6 +2008,30 @@ } } + { + // sub(add(X,Y), s/umin(X,Y)) --> s/umax(X,Y) + // sub(add(X,Y), s/umax(X,Y)) --> s/umin(X,Y) + // TODO: generalize to sub(add(Z,Y),umin(X,Y)) --> add(Z,usub.sat(Y,X))? + Value *X, *Y; + if (match(Op0, m_Add(m_Value(X), m_Value(Y)))) { + if (match(Op1, m_c_SMax(m_Specific(X), m_Specific(Y)))) + return replaceInstUsesWith( + I, Builder.CreateIntrinsic(Intrinsic::smin, {I.getType()}, {X, Y})); + + if (match(Op1, m_c_SMin(m_Specific(X), m_Specific(Y)))) + return replaceInstUsesWith( + I, Builder.CreateIntrinsic(Intrinsic::smax, {I.getType()}, {X, Y})); + + if (match(Op1, m_c_UMax(m_Specific(X), m_Specific(Y)))) + return replaceInstUsesWith( + I, Builder.CreateIntrinsic(Intrinsic::umin, {I.getType()}, {X, Y})); + + if (match(Op1, m_c_UMin(m_Specific(X), m_Specific(Y)))) + return replaceInstUsesWith( + I, Builder.CreateIntrinsic(Intrinsic::umax, {I.getType()}, {X, Y})); + } + } + { // If we have a subtraction between some value and a select between // said value and something else, sink subtraction into select hands, i.e.: diff --git a/llvm/test/Transforms/InstCombine/sub-minmax.ll b/llvm/test/Transforms/InstCombine/sub-minmax.ll --- a/llvm/test/Transforms/InstCombine/sub-minmax.ll +++ b/llvm/test/Transforms/InstCombine/sub-minmax.ll @@ -622,16 +622,14 @@ } ; -; TODO: sub(add(X,Y), s/umin(X,Y)) --> s/umax(X,Y) -; TODO: sub(add(X,Y), s/umax(X,Y)) --> s/umin(X,Y) +; sub(add(X,Y), s/umin(X,Y)) --> s/umax(X,Y) +; sub(add(X,Y), s/umax(X,Y)) --> s/umin(X,Y) ; define i8 @diff_add_smin(i8 %x, i8 %y) { ; CHECK-LABEL: @diff_add_smin( -; CHECK-NEXT: [[A:%.*]] = add i8 [[X:%.*]], [[Y:%.*]] -; CHECK-NEXT: [[M:%.*]] = call i8 @llvm.smin.i8(i8 [[X]], i8 [[Y]]) -; CHECK-NEXT: [[S:%.*]] = sub i8 [[A]], [[M]] -; CHECK-NEXT: ret i8 [[S]] +; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.smax.i8(i8 [[X:%.*]], i8 [[Y:%.*]]) +; CHECK-NEXT: ret i8 [[TMP1]] ; %a = add i8 %x, %y %m = call i8 @llvm.smin.i8(i8 %x, i8 %y) @@ -641,10 +639,8 @@ define i8 @diff_add_smax(i8 %x, i8 %y) { ; CHECK-LABEL: @diff_add_smax( -; CHECK-NEXT: [[A:%.*]] = add i8 [[X:%.*]], [[Y:%.*]] -; CHECK-NEXT: [[M:%.*]] = call i8 @llvm.smax.i8(i8 [[Y]], i8 [[X]]) -; CHECK-NEXT: [[S:%.*]] = sub i8 [[A]], [[M]] -; CHECK-NEXT: ret i8 [[S]] +; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.smin.i8(i8 [[X:%.*]], i8 [[Y:%.*]]) +; CHECK-NEXT: ret i8 [[TMP1]] ; %a = add i8 %x, %y %m = call i8 @llvm.smax.i8(i8 %y, i8 %x) @@ -654,10 +650,8 @@ define i8 @diff_add_umin(i8 %x, i8 %y) { ; CHECK-LABEL: @diff_add_umin( -; CHECK-NEXT: [[A:%.*]] = add i8 [[X:%.*]], [[Y:%.*]] -; CHECK-NEXT: [[M:%.*]] = call i8 @llvm.umin.i8(i8 [[X]], i8 [[Y]]) -; CHECK-NEXT: [[S:%.*]] = sub i8 [[A]], [[M]] -; CHECK-NEXT: ret i8 [[S]] +; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.umax.i8(i8 [[X:%.*]], i8 [[Y:%.*]]) +; CHECK-NEXT: ret i8 [[TMP1]] ; %a = add i8 %x, %y %m = call i8 @llvm.umin.i8(i8 %x, i8 %y) @@ -667,10 +661,8 @@ define i8 @diff_add_umax(i8 %x, i8 %y) { ; CHECK-LABEL: @diff_add_umax( -; CHECK-NEXT: [[A:%.*]] = add i8 [[X:%.*]], [[Y:%.*]] -; CHECK-NEXT: [[M:%.*]] = call i8 @llvm.umax.i8(i8 [[Y]], i8 [[X]]) -; CHECK-NEXT: [[S:%.*]] = sub i8 [[A]], [[M]] -; CHECK-NEXT: ret i8 [[S]] +; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.umin.i8(i8 [[X:%.*]], i8 [[Y:%.*]]) +; CHECK-NEXT: ret i8 [[TMP1]] ; %a = add i8 %x, %y %m = call i8 @llvm.umax.i8(i8 %y, i8 %x) @@ -680,11 +672,10 @@ define i8 @diff_add_smin_use(i8 %x, i8 %y) { ; CHECK-LABEL: @diff_add_smin_use( -; CHECK-NEXT: [[A:%.*]] = add i8 [[X:%.*]], [[Y:%.*]] -; CHECK-NEXT: [[M:%.*]] = call i8 @llvm.smin.i8(i8 [[X]], i8 [[Y]]) -; CHECK-NEXT: [[S:%.*]] = sub i8 [[A]], [[M]] +; CHECK-NEXT: [[M:%.*]] = call i8 @llvm.smin.i8(i8 [[X:%.*]], i8 [[Y:%.*]]) +; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.smax.i8(i8 [[X]], i8 [[Y]]) ; CHECK-NEXT: call void @use8(i8 [[M]]) -; CHECK-NEXT: ret i8 [[S]] +; CHECK-NEXT: ret i8 [[TMP1]] ; %a = add i8 %x, %y %m = call i8 @llvm.smin.i8(i8 %x, i8 %y) @@ -696,10 +687,9 @@ define i8 @diff_add_use_smax(i8 %x, i8 %y) { ; CHECK-LABEL: @diff_add_use_smax( ; CHECK-NEXT: [[A:%.*]] = add i8 [[X:%.*]], [[Y:%.*]] -; CHECK-NEXT: [[M:%.*]] = call i8 @llvm.smax.i8(i8 [[Y]], i8 [[X]]) -; CHECK-NEXT: [[S:%.*]] = sub i8 [[A]], [[M]] +; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.smin.i8(i8 [[X]], i8 [[Y]]) ; CHECK-NEXT: call void @use8(i8 [[A]]) -; CHECK-NEXT: ret i8 [[S]] +; CHECK-NEXT: ret i8 [[TMP1]] ; %a = add i8 %x, %y %m = call i8 @llvm.smax.i8(i8 %y, i8 %x) @@ -712,10 +702,10 @@ ; CHECK-LABEL: @diff_add_use_umin_use( ; CHECK-NEXT: [[A:%.*]] = add i8 [[X:%.*]], [[Y:%.*]] ; CHECK-NEXT: [[M:%.*]] = call i8 @llvm.umin.i8(i8 [[X]], i8 [[Y]]) -; CHECK-NEXT: [[S:%.*]] = sub i8 [[A]], [[M]] +; CHECK-NEXT: [[TMP1:%.*]] = call i8 @llvm.umax.i8(i8 [[X]], i8 [[Y]]) ; CHECK-NEXT: call void @use8(i8 [[A]]) ; CHECK-NEXT: call void @use8(i8 [[M]]) -; CHECK-NEXT: ret i8 [[S]] +; CHECK-NEXT: ret i8 [[TMP1]] ; %a = add i8 %x, %y %m = call i8 @llvm.umin.i8(i8 %x, i8 %y)