diff --git a/llvm/include/llvm/IR/PatternMatch.h b/llvm/include/llvm/IR/PatternMatch.h --- a/llvm/include/llvm/IR/PatternMatch.h +++ b/llvm/include/llvm/IR/PatternMatch.h @@ -2364,6 +2364,14 @@ m_CombineOr(m_c_UMax(L, R), m_c_UMin(L, R))); } +template +inline match_combine_or::Ty, + typename m_Intrinsic_Ty::Ty> +m_c_Intrinsic(const T0 &Op0, const T1 &Op1) { + return m_CombineOr(m_Intrinsic(Op0, Op1), + m_Intrinsic(Op1, Op0)); +} + /// Matches FAdd with LHS and RHS in either order. template inline BinaryOp_match 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 @@ -1811,6 +1811,20 @@ return replaceInstUsesWith(I, V); } + // minumum(X, Y) + maximum(X, Y) => X + Y. + if (match(&I, + m_c_FAdd(m_Intrinsic(m_Value(X), m_Value(Y)), + m_c_Intrinsic(m_Deferred(X), + m_Deferred(Y))))) { + BinaryOperator *Result = BinaryOperator::CreateFAddFMF(X, Y, &I); + // We cannot preserve ninf if nnan flag is not set. + // If X is NaN and Y is Inf then in original program we had NaN + NaN, + // while in optimized version NaN + Inf and this is a poison with ninf flag. + if (!Result->hasNoNaNs()) + Result->setHasNoInfs(false); + return Result; + } + return nullptr; } diff --git a/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp b/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp --- a/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp @@ -772,6 +772,20 @@ I.hasNoSignedZeros() && match(Start, m_Zero())) return replaceInstUsesWith(I, Start); + // minimun(X, Y) * maximum(X, Y) => X * Y. + if (match(&I, + m_c_FMul(m_Intrinsic(m_Value(X), m_Value(Y)), + m_c_Intrinsic(m_Deferred(X), + m_Deferred(Y))))) { + BinaryOperator *Result = BinaryOperator::CreateFMulFMF(X, Y, &I); + // We cannot preserve ninf if nnan flag is not set. + // If X is NaN and Y is Inf then in original program we had NaN * NaN, + // while in optimized version NaN * Inf and this is a poison with ninf flag. + if (!Result->hasNoNaNs()) + Result->setHasNoInfs(false); + return Result; + } + return nullptr; } diff --git a/llvm/test/Transforms/InstCombine/fadd-maximum-minimum.ll b/llvm/test/Transforms/InstCombine/fadd-maximum-minimum.ll --- a/llvm/test/Transforms/InstCombine/fadd-maximum-minimum.ll +++ b/llvm/test/Transforms/InstCombine/fadd-maximum-minimum.ll @@ -9,9 +9,7 @@ define float @test(float %a, float %b) { ; CHECK-LABEL: @test( ; CHECK-NEXT: entry: -; CHECK-NEXT: [[MIN:%.*]] = call float @llvm.minimum.f32(float [[A:%.*]], float [[B:%.*]]) -; CHECK-NEXT: [[MAX:%.*]] = call float @llvm.maximum.f32(float [[A]], float [[B]]) -; CHECK-NEXT: [[RES:%.*]] = fadd float [[MIN]], [[MAX]] +; CHECK-NEXT: [[RES:%.*]] = fadd float [[A:%.*]], [[B:%.*]] ; CHECK-NEXT: ret float [[RES]] ; entry: @@ -24,9 +22,7 @@ define float @test_comm1(float %a, float %b) { ; CHECK-LABEL: @test_comm1( ; CHECK-NEXT: entry: -; CHECK-NEXT: [[MIN:%.*]] = call float @llvm.minimum.f32(float [[A:%.*]], float [[B:%.*]]) -; CHECK-NEXT: [[MAX:%.*]] = call float @llvm.maximum.f32(float [[A]], float [[B]]) -; CHECK-NEXT: [[RES:%.*]] = fadd float [[MAX]], [[MIN]] +; CHECK-NEXT: [[RES:%.*]] = fadd float [[A:%.*]], [[B:%.*]] ; CHECK-NEXT: ret float [[RES]] ; entry: @@ -39,9 +35,7 @@ define float @test_comm2(float %a, float %b) { ; CHECK-LABEL: @test_comm2( ; CHECK-NEXT: entry: -; CHECK-NEXT: [[MIN:%.*]] = call float @llvm.minimum.f32(float [[A:%.*]], float [[B:%.*]]) -; CHECK-NEXT: [[MAX:%.*]] = call float @llvm.maximum.f32(float [[B]], float [[A]]) -; CHECK-NEXT: [[RES:%.*]] = fadd float [[MIN]], [[MAX]] +; CHECK-NEXT: [[RES:%.*]] = fadd float [[B:%.*]], [[A:%.*]] ; CHECK-NEXT: ret float [[RES]] ; entry: @@ -54,9 +48,7 @@ define float @test_comm3(float %a, float %b) { ; CHECK-LABEL: @test_comm3( ; CHECK-NEXT: entry: -; CHECK-NEXT: [[MIN:%.*]] = call float @llvm.minimum.f32(float [[A:%.*]], float [[B:%.*]]) -; CHECK-NEXT: [[MAX:%.*]] = call float @llvm.maximum.f32(float [[B]], float [[A]]) -; CHECK-NEXT: [[RES:%.*]] = fadd float [[MAX]], [[MIN]] +; CHECK-NEXT: [[RES:%.*]] = fadd float [[B:%.*]], [[A:%.*]] ; CHECK-NEXT: ret float [[RES]] ; entry: @@ -69,9 +61,7 @@ define <4 x float> @test_vect(<4 x float> %a, <4 x float> %b) { ; CHECK-LABEL: @test_vect( ; CHECK-NEXT: entry: -; CHECK-NEXT: [[MIN:%.*]] = call <4 x float> @llvm.minimum.v4f32(<4 x float> [[A:%.*]], <4 x float> [[B:%.*]]) -; CHECK-NEXT: [[MAX:%.*]] = call <4 x float> @llvm.maximum.v4f32(<4 x float> [[B]], <4 x float> [[A]]) -; CHECK-NEXT: [[RES:%.*]] = fadd <4 x float> [[MIN]], [[MAX]] +; CHECK-NEXT: [[RES:%.*]] = fadd <4 x float> [[B:%.*]], [[A:%.*]] ; CHECK-NEXT: ret <4 x float> [[RES]] ; entry: @@ -84,9 +74,7 @@ define float @test_flags(float %a, float %b) { ; CHECK-LABEL: @test_flags( ; CHECK-NEXT: entry: -; CHECK-NEXT: [[MIN:%.*]] = call float @llvm.minimum.f32(float [[A:%.*]], float [[B:%.*]]) -; CHECK-NEXT: [[MAX:%.*]] = call float @llvm.maximum.f32(float [[A]], float [[B]]) -; CHECK-NEXT: [[RES:%.*]] = fadd fast float [[MIN]], [[MAX]] +; CHECK-NEXT: [[RES:%.*]] = fadd fast float [[A:%.*]], [[B:%.*]] ; CHECK-NEXT: ret float [[RES]] ; entry: @@ -99,9 +87,7 @@ define float @test_flags2(float %a, float %b) { ; CHECK-LABEL: @test_flags2( ; CHECK-NEXT: entry: -; CHECK-NEXT: [[MIN:%.*]] = call float @llvm.minimum.f32(float [[A:%.*]], float [[B:%.*]]) -; CHECK-NEXT: [[MAX:%.*]] = call float @llvm.maximum.f32(float [[A]], float [[B]]) -; CHECK-NEXT: [[RES:%.*]] = fadd reassoc ninf nsz arcp contract afn float [[MIN]], [[MAX]] +; CHECK-NEXT: [[RES:%.*]] = fadd reassoc nsz arcp contract afn float [[A:%.*]], [[B:%.*]] ; CHECK-NEXT: ret float [[RES]] ; entry: diff --git a/llvm/test/Transforms/InstCombine/fmul-maximum-minimum.ll b/llvm/test/Transforms/InstCombine/fmul-maximum-minimum.ll --- a/llvm/test/Transforms/InstCombine/fmul-maximum-minimum.ll +++ b/llvm/test/Transforms/InstCombine/fmul-maximum-minimum.ll @@ -9,9 +9,7 @@ define float @test(float %a, float %b) { ; CHECK-LABEL: @test( ; CHECK-NEXT: entry: -; CHECK-NEXT: [[MIN:%.*]] = call float @llvm.minimum.f32(float [[A:%.*]], float [[B:%.*]]) -; CHECK-NEXT: [[MAX:%.*]] = call float @llvm.maximum.f32(float [[A]], float [[B]]) -; CHECK-NEXT: [[RES:%.*]] = fmul float [[MIN]], [[MAX]] +; CHECK-NEXT: [[RES:%.*]] = fmul float [[A:%.*]], [[B:%.*]] ; CHECK-NEXT: ret float [[RES]] ; entry: @@ -24,9 +22,7 @@ define float @test_comm1(float %a, float %b) { ; CHECK-LABEL: @test_comm1( ; CHECK-NEXT: entry: -; CHECK-NEXT: [[MIN:%.*]] = call float @llvm.minimum.f32(float [[A:%.*]], float [[B:%.*]]) -; CHECK-NEXT: [[MAX:%.*]] = call float @llvm.maximum.f32(float [[A]], float [[B]]) -; CHECK-NEXT: [[RES:%.*]] = fmul float [[MAX]], [[MIN]] +; CHECK-NEXT: [[RES:%.*]] = fmul float [[A:%.*]], [[B:%.*]] ; CHECK-NEXT: ret float [[RES]] ; entry: @@ -39,9 +35,7 @@ define float @test_comm2(float %a, float %b) { ; CHECK-LABEL: @test_comm2( ; CHECK-NEXT: entry: -; CHECK-NEXT: [[MIN:%.*]] = call float @llvm.minimum.f32(float [[A:%.*]], float [[B:%.*]]) -; CHECK-NEXT: [[MAX:%.*]] = call float @llvm.maximum.f32(float [[B]], float [[A]]) -; CHECK-NEXT: [[RES:%.*]] = fmul float [[MIN]], [[MAX]] +; CHECK-NEXT: [[RES:%.*]] = fmul float [[B:%.*]], [[A:%.*]] ; CHECK-NEXT: ret float [[RES]] ; entry: @@ -55,9 +49,7 @@ define float @test_comm3(float %a, float %b) { ; CHECK-LABEL: @test_comm3( ; CHECK-NEXT: entry: -; CHECK-NEXT: [[MIN:%.*]] = call float @llvm.minimum.f32(float [[A:%.*]], float [[B:%.*]]) -; CHECK-NEXT: [[MAX:%.*]] = call float @llvm.maximum.f32(float [[B]], float [[A]]) -; CHECK-NEXT: [[RES:%.*]] = fmul float [[MAX]], [[MIN]] +; CHECK-NEXT: [[RES:%.*]] = fmul float [[B:%.*]], [[A:%.*]] ; CHECK-NEXT: ret float [[RES]] ; entry: @@ -70,9 +62,7 @@ define <4 x float> @test_vect(<4 x float> %a, <4 x float> %b) { ; CHECK-LABEL: @test_vect( ; CHECK-NEXT: entry: -; CHECK-NEXT: [[MIN:%.*]] = call <4 x float> @llvm.minimum.v4f32(<4 x float> [[A:%.*]], <4 x float> [[B:%.*]]) -; CHECK-NEXT: [[MAX:%.*]] = call <4 x float> @llvm.maximum.v4f32(<4 x float> [[B]], <4 x float> [[A]]) -; CHECK-NEXT: [[RES:%.*]] = fmul <4 x float> [[MIN]], [[MAX]] +; CHECK-NEXT: [[RES:%.*]] = fmul <4 x float> [[B:%.*]], [[A:%.*]] ; CHECK-NEXT: ret <4 x float> [[RES]] ; entry: @@ -85,9 +75,7 @@ define float @test_flags(float %a, float %b) { ; CHECK-LABEL: @test_flags( ; CHECK-NEXT: entry: -; CHECK-NEXT: [[MIN:%.*]] = call float @llvm.minimum.f32(float [[A:%.*]], float [[B:%.*]]) -; CHECK-NEXT: [[MAX:%.*]] = call float @llvm.maximum.f32(float [[A]], float [[B]]) -; CHECK-NEXT: [[RES:%.*]] = fmul fast float [[MIN]], [[MAX]] +; CHECK-NEXT: [[RES:%.*]] = fmul fast float [[A:%.*]], [[B:%.*]] ; CHECK-NEXT: ret float [[RES]] ; entry: @@ -100,9 +88,7 @@ define float @test_flags2(float %a, float %b) { ; CHECK-LABEL: @test_flags2( ; CHECK-NEXT: entry: -; CHECK-NEXT: [[MIN:%.*]] = call float @llvm.minimum.f32(float [[A:%.*]], float [[B:%.*]]) -; CHECK-NEXT: [[MAX:%.*]] = call float @llvm.maximum.f32(float [[A]], float [[B]]) -; CHECK-NEXT: [[RES:%.*]] = fmul reassoc ninf nsz arcp contract afn float [[MIN]], [[MAX]] +; CHECK-NEXT: [[RES:%.*]] = fmul reassoc nsz arcp contract afn float [[A:%.*]], [[B:%.*]] ; CHECK-NEXT: ret float [[RES]] ; entry: