diff --git a/llvm/lib/Analysis/InstructionSimplify.cpp b/llvm/lib/Analysis/InstructionSimplify.cpp --- a/llvm/lib/Analysis/InstructionSimplify.cpp +++ b/llvm/lib/Analysis/InstructionSimplify.cpp @@ -6105,6 +6105,27 @@ return nullptr; } +static Value *foldMinMaxOfIntrin(Intrinsic::ID IID, Value *Op0, Value *Op1) { + if (IID == Intrinsic::umax || IID == Intrinsic::umin) { + // umax(uadd.sat(X, Y), X) --> uadd.sat(X, Y) + // umin(uadd.sat(X, Y), X) --> X + if (match(Op0, + m_Intrinsic(m_Specific(Op1), m_Value())) || + match(Op0, + m_Intrinsic(m_Value(), m_Specific(Op1)))) + return IID == Intrinsic::umax ? Op0 : Op1; + // umax(usub.sat(X, Y), X) --> X + // umin(usub.sat(X, Y), X) --> usub.sat(X, Y) + if (match(Op0, + m_Intrinsic(m_Specific(Op1), m_Value())) || + match(Op0, + m_Intrinsic(m_Value(), m_Specific(Op1)))) + return IID == Intrinsic::umin ? Op0 : Op1; + } + + return nullptr; +} + static Value *simplifyBinaryIntrinsic(Function *F, Value *Op0, Value *Op1, const SimplifyQuery &Q) { Intrinsic::ID IID = F->getIntrinsicID(); @@ -6184,6 +6205,11 @@ if (Value *V = foldMinMaxSharedOp(IID, Op1, Op0)) return V; + if (Value *V = foldMinMaxOfIntrin(IID, Op0, Op1)) + return V; + if (Value *V = foldMinMaxOfIntrin(IID, Op1, Op0)) + return V; + ICmpInst::Predicate Pred = ICmpInst::getNonStrictPredicate(MinMaxIntrinsic::getPredicate(IID)); if (isICmpTrue(Pred, Op0, Op1, Q.getWithoutUndef(), RecursionLimit)) diff --git a/llvm/test/Transforms/InstSimplify/minmax-intrin.ll b/llvm/test/Transforms/InstSimplify/minmax-intrin.ll --- a/llvm/test/Transforms/InstSimplify/minmax-intrin.ll +++ b/llvm/test/Transforms/InstSimplify/minmax-intrin.ll @@ -21,8 +21,7 @@ define <2 x i8> @umax_uadd_sat(<2 x i8> %x, <2 x i8> %y) { ; CHECK-LABEL: @umax_uadd_sat( ; CHECK-NEXT: [[XX:%.*]] = call <2 x i8> @llvm.uadd.sat.v2i8(<2 x i8> [[X:%.*]], <2 x i8> [[Y:%.*]]) -; CHECK-NEXT: [[RET:%.*]] = call <2 x i8> @llvm.umax.v2i8(<2 x i8> [[X]], <2 x i8> [[XX]]) -; CHECK-NEXT: ret <2 x i8> [[RET]] +; CHECK-NEXT: ret <2 x i8> [[XX]] ; %xx = call <2 x i8> @llvm.uadd.sat.v2i8(<2 x i8> %x, <2 x i8> %y) %ret = call <2 x i8> @llvm.umax.v2i8(<2 x i8> %x, <2 x i8> %xx) @@ -31,9 +30,7 @@ define i8 @umin_uadd_sat(i8 %x, i8 %y) { ; CHECK-LABEL: @umin_uadd_sat( -; CHECK-NEXT: [[XX:%.*]] = call i8 @llvm.uadd.sat.i8(i8 [[X:%.*]], i8 [[Y:%.*]]) -; CHECK-NEXT: [[RET:%.*]] = call i8 @llvm.umin.i8(i8 [[XX]], i8 [[X]]) -; CHECK-NEXT: ret i8 [[RET]] +; CHECK-NEXT: ret i8 [[X:%.*]] ; %xx = call i8 @llvm.uadd.sat.i8(i8 %x, i8 %y) %ret = call i8 @llvm.umin.i8(i8 %xx, i8 %x) @@ -42,9 +39,7 @@ define i8 @umax_usub_sat(i8 %x, i8 %y) { ; CHECK-LABEL: @umax_usub_sat( -; CHECK-NEXT: [[XX:%.*]] = call i8 @llvm.usub.sat.i8(i8 [[X:%.*]], i8 [[Y:%.*]]) -; CHECK-NEXT: [[RET:%.*]] = call i8 @llvm.umax.i8(i8 [[X]], i8 [[XX]]) -; CHECK-NEXT: ret i8 [[RET]] +; CHECK-NEXT: ret i8 [[X:%.*]] ; %xx = call i8 @llvm.usub.sat.i8(i8 %x, i8 %y) %ret = call i8 @llvm.umax.i8(i8 %x, i8 %xx) @@ -54,8 +49,7 @@ define <2 x i8> @umin_usub_sat(<2 x i8> %x, <2 x i8> %y) { ; CHECK-LABEL: @umin_usub_sat( ; CHECK-NEXT: [[XX:%.*]] = call <2 x i8> @llvm.usub.sat.v2i8(<2 x i8> [[X:%.*]], <2 x i8> [[Y:%.*]]) -; CHECK-NEXT: [[RET:%.*]] = call <2 x i8> @llvm.umin.v2i8(<2 x i8> [[X]], <2 x i8> [[XX]]) -; CHECK-NEXT: ret <2 x i8> [[RET]] +; CHECK-NEXT: ret <2 x i8> [[XX]] ; %xx = call <2 x i8> @llvm.usub.sat.v2i8(<2 x i8> %x, <2 x i8> %y) %ret = call <2 x i8> @llvm.umin.v2i8(<2 x i8> %x, <2 x i8> %xx)