From 5751b4a21824873328e40f536e94da46ee7b11c3 Mon Sep 17 00:00:00 2001 From: Lewis Crawford Date: Tue, 13 May 2025 09:23:03 +0000 Subject: [PATCH 1/6] [InstSimplify] Optimize maximumnum and minimumnum Add support for the new maximumnum and minimumnum intrinsics in various optimizations in InstSimplify. Also, change the behavior of optimizing maxnum(sNaN, x) to simplify to qNaN instead of x to better match the LLVM IR spec, and add more tests for sNaN behavior for all 3 max/min intrinsic types. --- llvm/include/llvm/IR/PatternMatch.h | 15 + llvm/lib/Analysis/InstructionSimplify.cpp | 49 +- llvm/lib/Analysis/ValueTracking.cpp | 4 + .../Transforms/InstSimplify/fminmax-folds.ll | 931 +++++++++++++++++- 4 files changed, 978 insertions(+), 21 deletions(-) diff --git a/llvm/include/llvm/IR/PatternMatch.h b/llvm/include/llvm/IR/PatternMatch.h index 6242a686e7bc0..c4d1bd095847d 100644 --- a/llvm/include/llvm/IR/PatternMatch.h +++ b/llvm/include/llvm/IR/PatternMatch.h @@ -707,10 +707,25 @@ m_SpecificInt_ICMP(ICmpInst::Predicate Predicate, const APInt &Threshold) { struct is_nan { bool isValue(const APFloat &C) const { return C.isNaN(); } }; + +struct is_snan { + bool isValue(const APFloat &C) const { return C.isSignaling(); } +}; + +struct is_qnan { + bool isValue(const APFloat &C) const { return C.isNaN() && !C.isSignaling(); } +}; + /// Match an arbitrary NaN constant. This includes quiet and signalling nans. /// For vectors, this includes constants with undefined elements. inline cstfp_pred_ty m_NaN() { return cstfp_pred_ty(); } +/// Match quiet NaN constants, including vectors with undefined elements. +inline cstfp_pred_ty m_qNaN() { return cstfp_pred_ty(); } + +/// Match signalling NaN constants, including vectors with undefined elements. +inline cstfp_pred_ty m_sNaN() { return cstfp_pred_ty(); } + struct is_nonnan { bool isValue(const APFloat &C) const { return !C.isNaN(); } }; diff --git a/llvm/lib/Analysis/InstructionSimplify.cpp b/llvm/lib/Analysis/InstructionSimplify.cpp index 85e3be9cc45c3..49774bcb45585 100644 --- a/llvm/lib/Analysis/InstructionSimplify.cpp +++ b/llvm/lib/Analysis/InstructionSimplify.cpp @@ -6415,7 +6415,8 @@ static Value *foldMinMaxSharedOp(Intrinsic::ID IID, Value *Op0, Value *Op1) { static Value *foldMinimumMaximumSharedOp(Intrinsic::ID IID, Value *Op0, Value *Op1) { assert((IID == Intrinsic::maxnum || IID == Intrinsic::minnum || - IID == Intrinsic::maximum || IID == Intrinsic::minimum) && + IID == Intrinsic::maximum || IID == Intrinsic::minimum || + IID == Intrinsic::maximumnum || IID == Intrinsic::minimumnum) && "Unsupported intrinsic"); auto *M0 = dyn_cast(Op0); @@ -6711,7 +6712,16 @@ Value *llvm::simplifyBinaryIntrinsic(Intrinsic::ID IID, Type *ReturnType, case Intrinsic::maxnum: case Intrinsic::minnum: case Intrinsic::maximum: - case Intrinsic::minimum: { + case Intrinsic::minimum: + case Intrinsic::maximumnum: + case Intrinsic::minimumnum: { + // In several cases here, we deviate from exact IEEE 754 semantics + // to enable optimizations (as allowed by the LLVM IR spec). + // + // For instance, we often return one of the arguments unmodified instead of + // inserting an llvm.canonicalize to transform input sNaNs into qNaNs or to + // respect any FTZ semantics, and sometimes assume all NaN inputs are qNaNs. + // If the arguments are the same, this is a no-op. if (Op0 == Op1) return Op0; @@ -6725,32 +6735,43 @@ Value *llvm::simplifyBinaryIntrinsic(Intrinsic::ID IID, Type *ReturnType, return Op0; bool PropagateNaN = IID == Intrinsic::minimum || IID == Intrinsic::maximum; - bool IsMin = IID == Intrinsic::minimum || IID == Intrinsic::minnum; - - // minnum(X, nan) -> X - // maxnum(X, nan) -> X - // minimum(X, nan) -> nan - // maximum(X, nan) -> nan - if (match(Op1, m_NaN())) - return PropagateNaN ? propagateNaN(cast(Op1)) : Op0; + bool PropagateSNaN = IID == Intrinsic::minnum || IID == Intrinsic::maxnum; + bool IsMin = IID == Intrinsic::minimum || IID == Intrinsic::minnum || + IID == Intrinsic::minimumnum; + + // minnum(x, qnan) -> x + // maxnum(x, qnan) -> x + // minnum(x, snan) -> qnan + // maxnum(x, snan) -> qnan + // minimum(X, nan) -> qnan + // maximum(X, nan) -> qnan + if (match(Op1, m_NaN())) { + if (PropagateNaN || (PropagateSNaN && match(Op1, m_sNaN()))) + return propagateNaN(cast(Op1)); + return Op0; + } // In the following folds, inf can be replaced with the largest finite // float, if the ninf flag is set. const APFloat *C; if (match(Op1, m_APFloat(C)) && (C->isInfinity() || (Call && Call->hasNoInfs() && C->isLargest()))) { - // minnum(X, -inf) -> -inf - // maxnum(X, +inf) -> +inf + // minnum(X, -inf) -> -inf (ignoring sNaN -> qNaN propagation) + // maxnum(X, +inf) -> +inf (ignoring sNaN -> qNaN propagation) // minimum(X, -inf) -> -inf if nnan // maximum(X, +inf) -> +inf if nnan + // minimumnum(X, -inf) -> -inf + // maximumnum(X, +inf) -> +inf if (C->isNegative() == IsMin && (!PropagateNaN || (Call && Call->hasNoNaNs()))) return ConstantFP::get(ReturnType, *C); // minnum(X, +inf) -> X if nnan // maxnum(X, -inf) -> X if nnan - // minimum(X, +inf) -> X - // maximum(X, -inf) -> X + // minimum(X, +inf) -> X (ignoring quieting of sNaNs) + // maximum(X, -inf) -> X (ignoring quieting of sNaNs) + // maximumnum(X, -inf) -> X if nnan + // minimumnum(X, +inf) -> X if nnan if (C->isNegative() != IsMin && (PropagateNaN || (Call && Call->hasNoNaNs()))) return Op0; diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp index 3d403531cea2f..a06241cb349bd 100644 --- a/llvm/lib/Analysis/ValueTracking.cpp +++ b/llvm/lib/Analysis/ValueTracking.cpp @@ -9310,6 +9310,10 @@ Intrinsic::ID llvm::getInverseMinMaxIntrinsic(Intrinsic::ID MinMaxID) { case Intrinsic::minimum: return Intrinsic::maximum; case Intrinsic::maxnum: return Intrinsic::minnum; case Intrinsic::minnum: return Intrinsic::maxnum; + case Intrinsic::maximumnum: + return Intrinsic::minimumnum; + case Intrinsic::minimumnum: + return Intrinsic::maximumnum; default: llvm_unreachable("Unexpected intrinsic"); } } diff --git a/llvm/test/Transforms/InstSimplify/fminmax-folds.ll b/llvm/test/Transforms/InstSimplify/fminmax-folds.ll index fff6cfd8a3b4b..ae5b965ff2723 100644 --- a/llvm/test/Transforms/InstSimplify/fminmax-folds.ll +++ b/llvm/test/Transforms/InstSimplify/fminmax-folds.ll @@ -54,6 +54,70 @@ define float @test_minimum_const_nan(float %x) { ret float %r } +define float @test_maximumnum_const_nan(float %x) { +; CHECK-LABEL: @test_maximumnum_const_nan( +; CHECK-NEXT: ret float [[R:%.*]] +; + %r = call float @llvm.maximumnum.f32(float %x, float 0x7fff000000000000) + ret float %r +} + +define float @test_minimumnum_const_nan(float %x) { +; CHECK-LABEL: @test_minimumnum_const_nan( +; CHECK-NEXT: ret float [[R:%.*]] +; + %r = call float @llvm.minimumnum.f32(float %x, float 0x7fff000000000000) + ret float %r +} + +define float @test_minnum_const_snan(float %x) { +; CHECK-LABEL: @test_minnum_const_snan( +; CHECK-NEXT: ret float 0x7FFC000000000000 +; + %r = call float @llvm.minnum.f32(float %x, float 0x7ff4000000000000) + ret float %r +} + +define float @test_maxnum_const_snan(float %x) { +; CHECK-LABEL: @test_maxnum_const_snan( +; CHECK-NEXT: ret float 0x7FFC000000000000 +; + %r = call float @llvm.maxnum.f32(float %x, float 0x7ff4000000000000) + ret float %r +} + +define float @test_maximum_const_snan(float %x) { +; CHECK-LABEL: @test_maximum_const_snan( +; CHECK-NEXT: ret float 0x7FFC000000000000 +; + %r = call float @llvm.maximum.f32(float %x, float 0x7ff4000000000000) + ret float %r +} + +define float @test_minimum_const_snan(float %x) { +; CHECK-LABEL: @test_minimum_const_snan( +; CHECK-NEXT: ret float 0x7FFC000000000000 +; + %r = call float @llvm.minimum.f32(float %x, float 0x7ff4000000000000) + ret float %r +} + +define float @test_maximumnum_const_snan(float %x) { +; CHECK-LABEL: @test_maximumnum_const_snan( +; CHECK-NEXT: ret float [[X:%.*]] +; + %r = call float @llvm.maximumnum.f32(float %x, float 0x7ff4000000000000) + ret float %r +} + +define float @test_minimumnum_const_snan(float %x) { +; CHECK-LABEL: @test_minimumnum_const_snan( +; CHECK-NEXT: ret float [[X:%.*]] +; + %r = call float @llvm.minimumnum.f32(float %x, float 0x7ff4000000000000) + ret float %r +} + define float @test_minnum_const_inf(float %x) { ; CHECK-LABEL: @test_minnum_const_inf( ; CHECK-NEXT: [[R:%.*]] = call float @llvm.minnum.f32(float [[X:%.*]], float 0x7FF0000000000000) @@ -88,6 +152,23 @@ define float @test_minimum_const_inf(float %x) { ret float %r } +define float @test_maximumnum_const_inf(float %x) { +; CHECK-LABEL: @test_maximumnum_const_inf( +; CHECK-NEXT: ret float 0x7FF0000000000000 +; + %r = call float @llvm.maximumnum.f32(float %x, float 0x7ff0000000000000) + ret float %r +} + +define float @test_minimumnum_const_inf(float %x) { +; CHECK-LABEL: @test_minimumnum_const_inf( +; CHECK-NEXT: [[R:%.*]] = call float @llvm.minimumnum.f32(float [[X:%.*]], float 0x7FF0000000000000) +; CHECK-NEXT: ret float [[R]] +; + %r = call float @llvm.minimumnum.f32(float %x, float 0x7ff0000000000000) + ret float %r +} + define float @test_minnum_const_neg_inf(float %x) { ; CHECK-LABEL: @test_minnum_const_neg_inf( ; CHECK-NEXT: ret float 0xFFF0000000000000 @@ -122,6 +203,23 @@ define float @test_minimum_const_neg_inf(float %x) { ret float %r } +define float @test_maximumnum_const_neg_inf(float %x) { +; CHECK-LABEL: @test_maximumnum_const_neg_inf( +; CHECK-NEXT: [[X:%.*]] = call float @llvm.maximumnum.f32(float [[X1:%.*]], float 0xFFF0000000000000) +; CHECK-NEXT: ret float [[X]] +; + %r = call float @llvm.maximumnum.f32(float %x, float 0xfff0000000000000) + ret float %r +} + +define float @test_minimumnum_const_neg_inf(float %x) { +; CHECK-LABEL: @test_minimumnum_const_neg_inf( +; CHECK-NEXT: ret float 0xFFF0000000000000 +; + %r = call float @llvm.minimumnum.f32(float %x, float 0xfff0000000000000) + ret float %r +} + define float @test_minnum_const_inf_nnan(float %x) { ; CHECK-LABEL: @test_minnum_const_inf_nnan( ; CHECK-NEXT: ret float [[X:%.*]] @@ -154,6 +252,22 @@ define float @test_minimum_const_inf_nnan(float %x) { ret float %r } +define float @test_maximumnum_const_inf_nnan(float %x) { +; CHECK-LABEL: @test_maximumnum_const_inf_nnan( +; CHECK-NEXT: ret float 0x7FF0000000000000 +; + %r = call nnan float @llvm.maximumnum.f32(float %x, float 0x7ff0000000000000) + ret float %r +} + +define float @test_minimumnum_const_inf_nnan(float %x) { +; CHECK-LABEL: @test_minimumnum_const_inf_nnan( +; CHECK-NEXT: ret float [[X:%.*]] +; + %r = call nnan float @llvm.minimumnum.f32(float %x, float 0x7ff0000000000000) + ret float %r +} + define float @test_minnum_const_inf_nnan_comm(float %x) { ; CHECK-LABEL: @test_minnum_const_inf_nnan_comm( ; CHECK-NEXT: ret float [[X:%.*]] @@ -186,6 +300,22 @@ define float @test_minimum_const_inf_nnan_comm(float %x) { ret float %r } +define float @test_maximumnum_const_inf_nnan_comm(float %x) { +; CHECK-LABEL: @test_maximumnum_const_inf_nnan_comm( +; CHECK-NEXT: ret float 0x7FF0000000000000 +; + %r = call nnan float @llvm.maximumnum.f32(float 0x7ff0000000000000, float %x) + ret float %r +} + +define float @test_minimumnum_const_inf_nnan_comm(float %x) { +; CHECK-LABEL: @test_minimumnum_const_inf_nnan_comm( +; CHECK-NEXT: ret float [[X:%.*]] +; + %r = call nnan float @llvm.minimumnum.f32(float 0x7ff0000000000000, float %x) + ret float %r +} + define <2 x float> @test_minnum_const_inf_nnan_comm_vec(<2 x float> %x) { ; CHECK-LABEL: @test_minnum_const_inf_nnan_comm_vec( ; CHECK-NEXT: ret <2 x float> [[X:%.*]] @@ -218,6 +348,22 @@ define <2 x float> @test_minimum_const_inf_nnan_comm_vec(<2 x float> %x) { ret <2 x float> %r } +define <2 x float> @test_maximumnum_const_inf_nnan_comm_vec(<2 x float> %x) { +; CHECK-LABEL: @test_maximumnum_const_inf_nnan_comm_vec( +; CHECK-NEXT: ret <2 x float> splat (float 0x7FF0000000000000) +; + %r = call nnan <2 x float> @llvm.maximumnum.v2f32(<2 x float> , <2 x float> %x) + ret <2 x float> %r +} + +define <2 x float> @test_minimumnum_const_inf_nnan_comm_vec(<2 x float> %x) { +; CHECK-LABEL: @test_minimumnum_const_inf_nnan_comm_vec( +; CHECK-NEXT: ret <2 x float> [[X:%.*]] +; + %r = call nnan <2 x float> @llvm.minimumnum.v2f32(<2 x float> , <2 x float> %x) + ret <2 x float> %r +} + define float @test_minnum_const_neg_inf_nnan(float %x) { ; CHECK-LABEL: @test_minnum_const_neg_inf_nnan( ; CHECK-NEXT: ret float 0xFFF0000000000000 @@ -250,6 +396,22 @@ define float @test_minimum_const_neg_inf_nnan(float %x) { ret float %r } +define float @test_maximumnum_const_neg_inf_nnan(float %x) { +; CHECK-LABEL: @test_maximumnum_const_neg_inf_nnan( +; CHECK-NEXT: ret float [[X:%.*]] +; + %r = call nnan float @llvm.maximumnum.f32(float %x, float 0xfff0000000000000) + ret float %r +} + +define float @test_minimumnum_const_neg_inf_nnan(float %x) { +; CHECK-LABEL: @test_minimumnum_const_neg_inf_nnan( +; CHECK-NEXT: ret float 0xFFF0000000000000 +; + %r = call nnan float @llvm.minimumnum.f32(float %x, float 0xfff0000000000000) + ret float %r +} + define float @test_minnum_const_max(float %x) { ; CHECK-LABEL: @test_minnum_const_max( ; CHECK-NEXT: [[R:%.*]] = call float @llvm.minnum.f32(float [[X:%.*]], float 0x47EFFFFFE0000000) @@ -286,6 +448,24 @@ define float @test_minimum_const_max(float %x) { ret float %r } +define float @test_maximumnum_const_max(float %x) { +; CHECK-LABEL: @test_maximumnum_const_max( +; CHECK-NEXT: [[R:%.*]] = call float @llvm.maximumnum.f32(float [[X:%.*]], float 0x47EFFFFFE0000000) +; CHECK-NEXT: ret float [[R]] +; + %r = call float @llvm.maximumnum.f32(float %x, float 0x47efffffe0000000) + ret float %r +} + +define float @test_minimumnum_const_max(float %x) { +; CHECK-LABEL: @test_minimumnum_const_max( +; CHECK-NEXT: [[R:%.*]] = call float @llvm.minimumnum.f32(float [[X:%.*]], float 0x47EFFFFFE0000000) +; CHECK-NEXT: ret float [[R]] +; + %r = call float @llvm.minimumnum.f32(float %x, float 0x47efffffe0000000) + ret float %r +} + define float @test_minnum_const_neg_max(float %x) { ; CHECK-LABEL: @test_minnum_const_neg_max( ; CHECK-NEXT: [[R:%.*]] = call float @llvm.minnum.f32(float [[X:%.*]], float 0xC7EFFFFFE0000000) @@ -322,6 +502,24 @@ define float @test_minimum_const_neg_max(float %x) { ret float %r } +define float @test_maximumnum_const_neg_max(float %x) { +; CHECK-LABEL: @test_maximumnum_const_neg_max( +; CHECK-NEXT: [[R:%.*]] = call float @llvm.maximumnum.f32(float [[X:%.*]], float 0xC7EFFFFFE0000000) +; CHECK-NEXT: ret float [[R]] +; + %r = call float @llvm.maximumnum.f32(float %x, float 0xc7efffffe0000000) + ret float %r +} + +define float @test_minimumnum_const_neg_max(float %x) { +; CHECK-LABEL: @test_minimumnum_const_neg_max( +; CHECK-NEXT: [[R:%.*]] = call float @llvm.minimumnum.f32(float [[X:%.*]], float 0xC7EFFFFFE0000000) +; CHECK-NEXT: ret float [[R]] +; + %r = call float @llvm.minimumnum.f32(float %x, float 0xc7efffffe0000000) + ret float %r +} + define float @test_minnum_const_max_ninf(float %x) { ; CHECK-LABEL: @test_minnum_const_max_ninf( ; CHECK-NEXT: [[R:%.*]] = call ninf float @llvm.minnum.f32(float [[X:%.*]], float 0x47EFFFFFE0000000) @@ -356,6 +554,23 @@ define float @test_minimum_const_max_ninf(float %x) { ret float %r } +define float @test_maximumnum_const_max_ninf(float %x) { +; CHECK-LABEL: @test_maximumnum_const_max_ninf( +; CHECK-NEXT: ret float 0x47EFFFFFE0000000 +; + %r = call ninf float @llvm.maximumnum.f32(float %x, float 0x47efffffe0000000) + ret float %r +} + +define float @test_minimumnum_const_max_ninf(float %x) { +; CHECK-LABEL: @test_minimumnum_const_max_ninf( +; CHECK-NEXT: [[R:%.*]] = call ninf float @llvm.minimumnum.f32(float [[X:%.*]], float 0x47EFFFFFE0000000) +; CHECK-NEXT: ret float [[R]] +; + %r = call ninf float @llvm.minimumnum.f32(float %x, float 0x47efffffe0000000) + ret float %r +} + define float @test_minnum_const_neg_max_ninf(float %x) { ; CHECK-LABEL: @test_minnum_const_neg_max_ninf( ; CHECK-NEXT: ret float 0xC7EFFFFFE0000000 @@ -390,6 +605,23 @@ define float @test_minimum_const_neg_max_ninf(float %x) { ret float %r } +define float @test_maximumnum_const_neg_max_ninf(float %x) { +; CHECK-LABEL: @test_maximumnum_const_neg_max_ninf( +; CHECK-NEXT: [[X:%.*]] = call ninf float @llvm.maximumnum.f32(float [[X1:%.*]], float 0xC7EFFFFFE0000000) +; CHECK-NEXT: ret float [[X]] +; + %r = call ninf float @llvm.maximumnum.f32(float %x, float 0xc7efffffe0000000) + ret float %r +} + +define float @test_minimumnum_const_neg_max_ninf(float %x) { +; CHECK-LABEL: @test_minimumnum_const_neg_max_ninf( +; CHECK-NEXT: ret float 0xC7EFFFFFE0000000 +; + %r = call ninf float @llvm.minimumnum.f32(float %x, float 0xc7efffffe0000000) + ret float %r +} + define float @test_minnum_const_max_nnan_ninf(float %x) { ; CHECK-LABEL: @test_minnum_const_max_nnan_ninf( ; CHECK-NEXT: ret float [[X:%.*]] @@ -422,6 +654,22 @@ define float @test_minimum_const_max_nnan_ninf(float %x) { ret float %r } +define float @test_maximumnum_const_max_nnan_ninf(float %x) { +; CHECK-LABEL: @test_maximumnum_const_max_nnan_ninf( +; CHECK-NEXT: ret float 0x47EFFFFFE0000000 +; + %r = call nnan ninf float @llvm.maximumnum.f32(float %x, float 0x47efffffe0000000) + ret float %r +} + +define float @test_minimumnum_const_max_nnan_ninf(float %x) { +; CHECK-LABEL: @test_minimumnum_const_max_nnan_ninf( +; CHECK-NEXT: ret float [[X:%.*]] +; + %r = call nnan ninf float @llvm.minimumnum.f32(float %x, float 0x47efffffe0000000) + ret float %r +} + define float @test_minnum_const_neg_max_nnan_ninf(float %x) { ; CHECK-LABEL: @test_minnum_const_neg_max_nnan_ninf( ; CHECK-NEXT: ret float 0xC7EFFFFFE0000000 @@ -454,8 +702,24 @@ define float @test_minimum_const_neg_max_nnan_ninf(float %x) { ret float %r } +define float @test_maximumnum_const_neg_max_nnan_ninf(float %x) { +; CHECK-LABEL: @test_maximumnum_const_neg_max_nnan_ninf( +; CHECK-NEXT: ret float [[X:%.*]] +; + %r = call nnan ninf float @llvm.maximumnum.f32(float %x, float 0xc7efffffe0000000) + ret float %r +} + +define float @test_minimumnum_const_neg_max_nnan_ninf(float %x) { +; CHECK-LABEL: @test_minimumnum_const_neg_max_nnan_ninf( +; CHECK-NEXT: ret float 0xC7EFFFFFE0000000 +; + %r = call nnan ninf float @llvm.minimumnum.f32(float %x, float 0xc7efffffe0000000) + ret float %r +} + ; From the LangRef for minnum/maxnum: -; "If either operand is a NaN, returns the other non-NaN operand." +; "If either operand is a qNaN, returns the other non-NaN operand. Returns NaN only if both operands are NaN or if either operand is sNaN." define double @maxnum_nan_op0(double %x) { ; CHECK-LABEL: @maxnum_nan_op0( @@ -521,6 +785,70 @@ define <2 x double> @minnum_nan_op1_vec(<2 x double> %x) { ret <2 x double> %r } +define double @maxnum_snan_op0(double %x) { +; CHECK-LABEL: @maxnum_snan_op0( +; CHECK-NEXT: ret double 0x7FFC000000000000 +; + %r = call double @llvm.maxnum.f64(double 0x7ff4000000000000, double %x) + ret double %r +} + +define double @maxnum_snan_op1(double %x) { +; CHECK-LABEL: @maxnum_snan_op1( +; CHECK-NEXT: ret double 0x7FFC00000000DEAD +; + %r = call double @llvm.maxnum.f64(double %x, double 0x7ff400000000dead) + ret double %r +} + +define double @minnum_snan_op0(double %x) { +; CHECK-LABEL: @minnum_snan_op0( +; CHECK-NEXT: ret double 0x7FFC000DEAD00000 +; + %r = call double @llvm.minnum.f64(double 0x7ff4000dead00000, double %x) + ret double %r +} + +define double @minnum_snan_op1(double %x) { +; CHECK-LABEL: @minnum_snan_op1( +; CHECK-NEXT: ret double 0x7FFC00DEAD00DEAD +; + %r = call double @llvm.minnum.f64(double %x, double 0x7ff400dead00dead) + ret double %r +} + +define <2 x double> @maxnum_snan_op0_vec(<2 x double> %x) { +; CHECK-LABEL: @maxnum_snan_op0_vec( +; CHECK-NEXT: ret <2 x double> +; + %r = call <2 x double> @llvm.maxnum.v2f64(<2 x double> , <2 x double> %x) + ret <2 x double> %r +} + +define <2 x double> @maxnum_snan_op1_vec(<2 x double> %x) { +; CHECK-LABEL: @maxnum_snan_op1_vec( +; CHECK-NEXT: ret <2 x double> +; + %r = call <2 x double> @llvm.maxnum.v2f64(<2 x double> %x, <2 x double> ) + ret <2 x double> %r +} + +define <2 x double> @minnum_snan_op0_vec(<2 x double> %x) { +; CHECK-LABEL: @minnum_snan_op0_vec( +; CHECK-NEXT: ret <2 x double> +; + %r = call <2 x double> @llvm.minnum.v2f64(<2 x double> , <2 x double> %x) + ret <2 x double> %r +} + +define <2 x double> @minnum_snan_op1_vec(<2 x double> %x) { +; CHECK-LABEL: @minnum_snan_op1_vec( +; CHECK-NEXT: ret <2 x double> splat (double 0x7FFC00DEAD00DEAD) +; + %r = call <2 x double> @llvm.minnum.v2f64(<2 x double> %x, <2 x double> ) + ret <2 x double> %r +} + define float @maxnum_undef_op1(float %x) { ; CHECK-LABEL: @maxnum_undef_op1( ; CHECK-NEXT: ret float [[X:%.*]] @@ -609,6 +937,14 @@ define float @minnum_undef_poison(float %x) { ret float %val } +define float @minnum_poison_poison(float %x) { +; CHECK-LABEL: @minnum_poison_poison( +; CHECK-NEXT: ret float poison +; + %val = call float @llvm.minnum.f32(float poison, float poison) + ret float %val +} + define float @maxnum_undef_undef(float %x) { ; CHECK-LABEL: @maxnum_undef_undef( ; CHECK-NEXT: ret float undef @@ -633,6 +969,14 @@ define float @maxnum_undef_poison(float %x) { ret float %val } +define float @maxnum_poison_poison(float %x) { +; CHECK-LABEL: @maxnum_poison_poison( +; CHECK-NEXT: ret float poison +; + %val = call float @llvm.maxnum.f32(float poison, float poison) + ret float %val +} + define float @minnum_same_args(float %x) { ; CHECK-LABEL: @minnum_same_args( ; CHECK-NEXT: ret float [[X:%.*]] @@ -743,6 +1087,7 @@ define float @minnum_inf(float %x) { %val = call float @llvm.minnum.f32(float 0x7FF0000000000000, float %x) ret float %val } + define float @maxnum_x_maxnum_x_y(float %x, float %y) { ; CHECK-LABEL: @maxnum_x_maxnum_x_y( ; CHECK-NEXT: [[A:%.*]] = call float @llvm.maxnum.f32(float [[X:%.*]], float [[Y:%.*]]) @@ -921,6 +1266,86 @@ define <2 x double> @minimum_nan_op1_vec(<2 x double> %x) { ret <2 x double> %r } +define double @maximum_snan_op0(double %x) { +; CHECK-LABEL: @maximum_snan_op0( +; CHECK-NEXT: ret double 0x7FFC000000000000 +; + %r = call double @llvm.maximum.f64(double 0x7ff4000000000000, double %x) + ret double %r +} + +define double @maximum_snan_op1(double %x) { +; CHECK-LABEL: @maximum_snan_op1( +; CHECK-NEXT: ret double 0x7FFC00000000DEAD +; + %r = call double @llvm.maximum.f64(double %x, double 0x7ff400000000dead) + ret double %r +} + +define double @minimum_snan_op0(double %x) { +; CHECK-LABEL: @minimum_snan_op0( +; CHECK-NEXT: ret double 0x7FFC000DEAD00000 +; + %r = call double @llvm.minimum.f64(double 0x7ff4000dead00000, double %x) + ret double %r +} + +define double @minimum_snan_op1(double %x) { +; CHECK-LABEL: @minimum_snan_op1( +; CHECK-NEXT: ret double 0x7FFC00DEAD00DEAD +; + %r = call double @llvm.minimum.f64(double %x, double 0x7ff400dead00dead) + ret double %r +} + +define <2 x double> @maximum_snan_op0_vec_partial_poison(<2 x double> %x) { +; CHECK-LABEL: @maximum_snan_op0_vec_partial_poison( +; CHECK-NEXT: ret <2 x double> +; + %r = call <2 x double> @llvm.maximum.v2f64(<2 x double> , <2 x double> %x) + ret <2 x double> %r +} + +define <2 x double> @maximum_snan_op1_vec_partial_poison(<2 x double> %x) { +; CHECK-LABEL: @maximum_snan_op1_vec_partial_poison( +; CHECK-NEXT: ret <2 x double> +; + %r = call <2 x double> @llvm.maximum.v2f64(<2 x double> %x, <2 x double> ) + ret <2 x double> %r +} + +define <2 x double> @maximum_snan_op1_vec(<2 x double> %x) { +; CHECK-LABEL: @maximum_snan_op1_vec( +; CHECK-NEXT: ret <2 x double> +; + %r = call <2 x double> @llvm.maximum.v2f64(<2 x double> %x, <2 x double> ) + ret <2 x double> %r +} + +define <2 x double> @minimum_snan_op0_vec_partial_poison(<2 x double> %x) { +; CHECK-LABEL: @minimum_snan_op0_vec_partial_poison( +; CHECK-NEXT: ret <2 x double> +; + %r = call <2 x double> @llvm.minimum.v2f64(<2 x double> , <2 x double> %x) + ret <2 x double> %r +} + +define <2 x double> @minimum_snan_op1_vec_partial_poison(<2 x double> %x) { +; CHECK-LABEL: @minimum_snan_op1_vec_partial_poison( +; CHECK-NEXT: ret <2 x double> +; + %r = call <2 x double> @llvm.minimum.v2f64(<2 x double> %x, <2 x double> ) + ret <2 x double> %r +} + +define <2 x double> @minimum_snan_op1_vec(<2 x double> %x) { +; CHECK-LABEL: @minimum_snan_op1_vec( +; CHECK-NEXT: ret <2 x double> splat (double 0x7FFC00DEAD00DEAD) +; + %r = call <2 x double> @llvm.minimum.v2f64(<2 x double> %x, <2 x double> ) + ret <2 x double> %r +} + define float @maximum_undef_op1(float %x) { ; CHECK-LABEL: @maximum_undef_op1( ; CHECK-NEXT: ret float [[X:%.*]] @@ -1001,6 +1426,22 @@ define float @maximum_undef_undef(float %x) { ret float %val } +define float @minimum_poison_poison(float %x) { +; CHECK-LABEL: @minimum_poison_poison( +; CHECK-NEXT: ret float poison +; + %val = call float @llvm.minimum.f32(float poison, float poison) + ret float %val +} + +define float @maximum_poison_poison(float %x) { +; CHECK-LABEL: @maximum_poison_poison( +; CHECK-NEXT: ret float poison +; + %val = call float @llvm.maximum.f32(float poison, float poison) + ret float %val +} + define float @minimum_same_args(float %x) { ; CHECK-LABEL: @minimum_same_args( ; CHECK-NEXT: ret float [[X:%.*]] @@ -1171,8 +1612,6 @@ define <2 x double> @minimum_neginf_commute_vec(<2 x double> %x) { ret <2 x double> %r } -; TODO: minimum(INF, X) --> X - define float @minimum_inf(float %x) { ; CHECK-LABEL: @minimum_inf( ; CHECK-NEXT: ret float [[X:%.*]] @@ -1317,8 +1756,8 @@ define <2 x float> @maxnum_minnum_maxnum(<2 x float> %x, <2 x float> %y) { ret <2 x float> %val } -define <2 x double> @maxnum_minnum_minmum(<2 x double> %x, <2 x double> %y) { -; CHECK-LABEL: @maxnum_minnum_minmum( +define <2 x double> @maxnum_minnum_minnum(<2 x double> %x, <2 x double> %y) { +; CHECK-LABEL: @maxnum_minnum_minnum( ; CHECK-NEXT: [[MIN1:%.*]] = call <2 x double> @llvm.minnum.v2f64(<2 x double> [[X:%.*]], <2 x double> [[Y:%.*]]) ; CHECK-NEXT: [[MIN2:%.*]] = call <2 x double> @llvm.minnum.v2f64(<2 x double> [[X]], <2 x double> [[Y]]) ; CHECK-NEXT: [[VAL:%.*]] = call <2 x double> @llvm.maxnum.v2f64(<2 x double> [[MIN1]], <2 x double> [[MIN2]]) @@ -1376,8 +1815,8 @@ define <2 x float> @minnum_maxnum_maxnum(<2 x float> %x, <2 x float> %y) { ret <2 x float> %val } -define <2 x double> @minnum_minnum_minmum(<2 x double> %x, <2 x double> %y) { -; CHECK-LABEL: @minnum_minnum_minmum( +define <2 x double> @minnum_minnum_minnum(<2 x double> %x, <2 x double> %y) { +; CHECK-LABEL: @minnum_minnum_minnum( ; CHECK-NEXT: [[MIN1:%.*]] = call <2 x double> @llvm.minnum.v2f64(<2 x double> [[X:%.*]], <2 x double> [[Y:%.*]]) ; CHECK-NEXT: ret <2 x double> [[MIN1]] ; @@ -1386,3 +1825,481 @@ define <2 x double> @minnum_minnum_minmum(<2 x double> %x, <2 x double> %y) { %val = call <2 x double> @llvm.minnum.v2f64(<2 x double> %min1, <2 x double> %min2) ret <2 x double> %val } + +; From the LangRef for minimumnum/maximumnum: +; "If both operands are NaNs (including sNaN), returns qNaN. +; If one operand is NaN (including sNaN) and another operand is a number, return the number." + +define double @maximumnum_nan_op0(double %x) { +; CHECK-LABEL: @maximumnum_nan_op0( +; CHECK-NEXT: ret double [[X:%.*]] +; + %r = call double @llvm.maximumnum.f64(double 0x7ff8000000000000, double %x) + ret double %r +} + +define double @maximumnum_nan_op1(double %x) { +; CHECK-LABEL: @maximumnum_nan_op1( +; CHECK-NEXT: ret double [[X:%.*]] +; + %r = call double @llvm.maximumnum.f64(double %x, double 0x7ff800000000dead) + ret double %r +} + +define double @minimumnum_nan_op0(double %x) { +; CHECK-LABEL: @minimumnum_nan_op0( +; CHECK-NEXT: ret double [[X:%.*]] +; + %r = call double @llvm.minimumnum.f64(double 0x7ff8000dead00000, double %x) + ret double %r +} + +define double @minimumnum_nan_op1(double %x) { +; CHECK-LABEL: @minimumnum_nan_op1( +; CHECK-NEXT: ret double [[X:%.*]] +; + %r = call double @llvm.minimumnum.f64(double %x, double 0x7ff800dead00dead) + ret double %r +} + +define <2 x double> @maximumnum_nan_op0_vec(<2 x double> %x) { +; CHECK-LABEL: @maximumnum_nan_op0_vec( +; CHECK-NEXT: ret <2 x double> [[X:%.*]] +; + %r = call <2 x double> @llvm.maximumnum.v2f64(<2 x double> , <2 x double> %x) + ret <2 x double> %r +} + +define <2 x double> @maximumnum_nan_op1_vec(<2 x double> %x) { +; CHECK-LABEL: @maximumnum_nan_op1_vec( +; CHECK-NEXT: ret <2 x double> [[X:%.*]] +; + %r = call <2 x double> @llvm.maximumnum.v2f64(<2 x double> %x, <2 x double> ) + ret <2 x double> %r +} + +define <2 x double> @minimumnum_nan_op0_vec(<2 x double> %x) { +; CHECK-LABEL: @minimumnum_nan_op0_vec( +; CHECK-NEXT: ret <2 x double> [[X:%.*]] +; + %r = call <2 x double> @llvm.minimumnum.v2f64(<2 x double> , <2 x double> %x) + ret <2 x double> %r +} + +define <2 x double> @minimumnum_nan_op1_vec(<2 x double> %x) { +; CHECK-LABEL: @minimumnum_nan_op1_vec( +; CHECK-NEXT: ret <2 x double> [[X:%.*]] +; + %r = call <2 x double> @llvm.minimumnum.v2f64(<2 x double> %x, <2 x double> ) + ret <2 x double> %r +} + +define double @maximumnum_snan_op0(double %x) { +; CHECK-LABEL: @maximumnum_snan_op0( +; CHECK-NEXT: ret double [[X:%.*]] +; + %r = call double @llvm.maximumnum.f64(double 0x7ff4000000000000, double %x) + ret double %r +} + +define double @maximumnum_snan_op1(double %x) { +; CHECK-LABEL: @maximumnum_snan_op1( +; CHECK-NEXT: ret double [[X:%.*]] +; + %r = call double @llvm.maximumnum.f64(double %x, double 0x7ff400000000dead) + ret double %r +} + +define double @minimumnum_snan_op0(double %x) { +; CHECK-LABEL: @minimumnum_snan_op0( +; CHECK-NEXT: ret double [[X:%.*]] +; + %r = call double @llvm.minimumnum.f64(double 0x7ff4000dead00000, double %x) + ret double %r +} + +define double @minimumnum_snan_op1(double %x) { +; CHECK-LABEL: @minimumnum_snan_op1( +; CHECK-NEXT: ret double [[X:%.*]] +; + %r = call double @llvm.minimumnum.f64(double %x, double 0x7ff400dead00dead) + ret double %r +} + +define <2 x double> @maximumnum_snan_op0_vec(<2 x double> %x) { +; CHECK-LABEL: @maximumnum_snan_op0_vec( +; CHECK-NEXT: ret <2 x double> [[X:%.*]] +; + %r = call <2 x double> @llvm.maximumnum.v2f64(<2 x double> , <2 x double> %x) + ret <2 x double> %r +} + +define <2 x double> @maximumnum_snan_op1_vec(<2 x double> %x) { +; CHECK-LABEL: @maximumnum_snan_op1_vec( +; CHECK-NEXT: ret <2 x double> [[X:%.*]] +; + %r = call <2 x double> @llvm.maximumnum.v2f64(<2 x double> %x, <2 x double> ) + ret <2 x double> %r +} + +define <2 x double> @minimumnum_snan_op0_vec(<2 x double> %x) { +; CHECK-LABEL: @minimumnum_snan_op0_vec( +; CHECK-NEXT: ret <2 x double> [[X:%.*]] +; + %r = call <2 x double> @llvm.minimumnum.v2f64(<2 x double> , <2 x double> %x) + ret <2 x double> %r +} + +define <2 x double> @minimumnum_snan_op1_vec(<2 x double> %x) { +; CHECK-LABEL: @minimumnum_snan_op1_vec( +; CHECK-NEXT: ret <2 x double> [[X:%.*]] +; + %r = call <2 x double> @llvm.minimumnum.v2f64(<2 x double> %x, <2 x double> ) + ret <2 x double> %r +} + +define float @maximumnum_poison_op1(float %x) { +; CHECK-LABEL: @maximumnum_poison_op1( +; CHECK-NEXT: ret float [[X:%.*]] +; + %val = call float @llvm.maximumnum.f32(float %x, float poison) + ret float %val +} + +define float @maximumnum_poison_op0(float %x) { +; CHECK-LABEL: @maximumnum_poison_op0( +; CHECK-NEXT: ret float [[X:%.*]] +; + %val = call float @llvm.maximumnum.f32(float poison, float %x) + ret float %val +} + +define float @minimumnum_poison_op1(float %x) { +; CHECK-LABEL: @minimumnum_poison_op1( +; CHECK-NEXT: ret float [[X:%.*]] +; + %val = call float @llvm.minimumnum.f32(float %x, float poison) + ret float %val +} + +define float @minimumnum_poison_op0(float %x) { +; CHECK-LABEL: @minimumnum_poison_op0( +; CHECK-NEXT: ret float [[X:%.*]] +; + %val = call float @llvm.minimumnum.f32(float poison, float %x) + ret float %val +} + +define float @minimumnum_poison_poison(float %x) { +; CHECK-LABEL: @minimumnum_poison_poison( +; CHECK-NEXT: ret float poison +; + %val = call float @llvm.minimumnum.f32(float poison, float poison) + ret float %val +} + +define float @maximumnum_poison_poison(float %x) { +; CHECK-LABEL: @maximumnum_poison_poison( +; CHECK-NEXT: ret float poison +; + %val = call float @llvm.maximumnum.f32(float poison, float poison) + ret float %val +} + +define float @minimumnum_same_args(float %x) { +; CHECK-LABEL: @minimumnum_same_args( +; CHECK-NEXT: ret float [[X:%.*]] +; + %y = call float @llvm.minimumnum.f32(float %x, float %x) + ret float %y +} + +define float @maximumnum_same_args(float %x) { +; CHECK-LABEL: @maximumnum_same_args( +; CHECK-NEXT: ret float [[X:%.*]] +; + %y = call float @llvm.maximumnum.f32(float %x, float %x) + ret float %y +} + +define float @minimumnum_x_minimumnum_x_y(float %x, float %y) { +; CHECK-LABEL: @minimumnum_x_minimumnum_x_y( +; CHECK-NEXT: [[A:%.*]] = call float @llvm.minimumnum.f32(float [[X:%.*]], float [[Y:%.*]]) +; CHECK-NEXT: ret float [[A]] +; + %a = call float @llvm.minimumnum.f32(float %x, float %y) + %b = call float @llvm.minimumnum.f32(float %x, float %a) + ret float %b +} + +define float @minimumnum_y_minimumnum_x_y(float %x, float %y) { +; CHECK-LABEL: @minimumnum_y_minimumnum_x_y( +; CHECK-NEXT: [[A:%.*]] = call float @llvm.minimumnum.f32(float [[X:%.*]], float [[Y:%.*]]) +; CHECK-NEXT: ret float [[A]] +; + %a = call float @llvm.minimumnum.f32(float %x, float %y) + %b = call float @llvm.minimumnum.f32(float %y, float %a) + ret float %b +} + +define float @minimumnum_x_y_minimumnum_x(float %x, float %y) { +; CHECK-LABEL: @minimumnum_x_y_minimumnum_x( +; CHECK-NEXT: [[A:%.*]] = call float @llvm.minimumnum.f32(float [[X:%.*]], float [[Y:%.*]]) +; CHECK-NEXT: ret float [[A]] +; + %a = call float @llvm.minimumnum.f32(float %x, float %y) + %b = call float @llvm.minimumnum.f32(float %a, float %x) + ret float %b +} + +define float @minimumnum_x_y_minimumnum_y(float %x, float %y) { +; CHECK-LABEL: @minimumnum_x_y_minimumnum_y( +; CHECK-NEXT: [[A:%.*]] = call float @llvm.minimumnum.f32(float [[X:%.*]], float [[Y:%.*]]) +; CHECK-NEXT: ret float [[A]] +; + %a = call float @llvm.minimumnum.f32(float %x, float %y) + %b = call float @llvm.minimumnum.f32(float %a, float %y) + ret float %b +} + +; negative test + +define float @minimumnum_z_minimumnum_x_y(float %x, float %y, float %z) { +; CHECK-LABEL: @minimumnum_z_minimumnum_x_y( +; CHECK-NEXT: [[A:%.*]] = call float @llvm.minimumnum.f32(float [[X:%.*]], float [[Y:%.*]]) +; CHECK-NEXT: [[B:%.*]] = call float @llvm.minimumnum.f32(float [[Z:%.*]], float [[A]]) +; CHECK-NEXT: ret float [[B]] +; + %a = call float @llvm.minimumnum.f32(float %x, float %y) + %b = call float @llvm.minimumnum.f32(float %z, float %a) + ret float %b +} + +; negative test + +define float @minimumnum_x_y_minimumnum_z(float %x, float %y, float %z) { +; CHECK-LABEL: @minimumnum_x_y_minimumnum_z( +; CHECK-NEXT: [[A:%.*]] = call float @llvm.minimumnum.f32(float [[X:%.*]], float [[Y:%.*]]) +; CHECK-NEXT: [[B:%.*]] = call float @llvm.minimumnum.f32(float [[A]], float [[Z:%.*]]) +; CHECK-NEXT: ret float [[B]] +; + %a = call float @llvm.minimumnum.f32(float %x, float %y) + %b = call float @llvm.minimumnum.f32(float %a, float %z) + ret float %b +} + +; minimumnum(X, -INF) --> -INF + +define float @minimumnum_neginf(float %x) { +; CHECK-LABEL: @minimumnum_neginf( +; CHECK-NEXT: ret float 0xFFF0000000000000 +; + %val = call float @llvm.minimumnum.f32(float %x, float 0xFFF0000000000000) + ret float %val +} + +define <2 x double> @minimumnum_neginf_commute_vec(<2 x double> %x) { +; CHECK-LABEL: @minimumnum_neginf_commute_vec( +; CHECK-NEXT: ret <2 x double> splat (double 0xFFF0000000000000) +; + %r = call <2 x double> @llvm.minimumnum.v2f64(<2 x double> , <2 x double> %x) + ret <2 x double> %r +} + +; negative test + +define float @minimumnum_inf(float %x) { +; CHECK-LABEL: @minimumnum_inf( +; CHECK-NEXT: [[VAL:%.*]] = call float @llvm.minimumnum.f32(float 0x7FF0000000000000, float [[X:%.*]]) +; CHECK-NEXT: ret float [[VAL]] +; + %val = call float @llvm.minimumnum.f32(float 0x7FF0000000000000, float %x) + ret float %val +} + +define float @maximumnum_x_maximumnum_x_y(float %x, float %y) { +; CHECK-LABEL: @maximumnum_x_maximumnum_x_y( +; CHECK-NEXT: [[A:%.*]] = call float @llvm.maximumnum.f32(float [[X:%.*]], float [[Y:%.*]]) +; CHECK-NEXT: ret float [[A]] +; + %a = call float @llvm.maximumnum.f32(float %x, float %y) + %b = call float @llvm.maximumnum.f32(float %x, float %a) + ret float %b +} + +define float @maximumnum_y_maximumnum_x_y(float %x, float %y) { +; CHECK-LABEL: @maximumnum_y_maximumnum_x_y( +; CHECK-NEXT: [[A:%.*]] = call float @llvm.maximumnum.f32(float [[X:%.*]], float [[Y:%.*]]) +; CHECK-NEXT: ret float [[A]] +; + %a = call float @llvm.maximumnum.f32(float %x, float %y) + %b = call float @llvm.maximumnum.f32(float %y, float %a) + ret float %b +} + +define float @maximumnum_x_y_maximumnum_x(float %x, float %y) { +; CHECK-LABEL: @maximumnum_x_y_maximumnum_x( +; CHECK-NEXT: [[A:%.*]] = call float @llvm.maximumnum.f32(float [[X:%.*]], float [[Y:%.*]]) +; CHECK-NEXT: ret float [[A]] +; + %a = call float @llvm.maximumnum.f32(float %x, float %y) + %b = call float @llvm.maximumnum.f32(float %a, float %x) + ret float %b +} + +define float @maximumnum_x_y_maximumnum_y(float %x, float %y) { +; CHECK-LABEL: @maximumnum_x_y_maximumnum_y( +; CHECK-NEXT: [[A:%.*]] = call float @llvm.maximumnum.f32(float [[X:%.*]], float [[Y:%.*]]) +; CHECK-NEXT: ret float [[A]] +; + %a = call float @llvm.maximumnum.f32(float %x, float %y) + %b = call float @llvm.maximumnum.f32(float %a, float %y) + ret float %b +} + +; negative test + +define float @maximumnum_z_maximumnum_x_y(float %x, float %y, float %z) { +; CHECK-LABEL: @maximumnum_z_maximumnum_x_y( +; CHECK-NEXT: [[A:%.*]] = call float @llvm.maximumnum.f32(float [[X:%.*]], float [[Y:%.*]]) +; CHECK-NEXT: [[B:%.*]] = call float @llvm.maximumnum.f32(float [[Z:%.*]], float [[A]]) +; CHECK-NEXT: ret float [[B]] +; + %a = call float @llvm.maximumnum.f32(float %x, float %y) + %b = call float @llvm.maximumnum.f32(float %z, float %a) + ret float %b +} + +; negative test + +define float @maximumnum_x_y_maximumnum_z(float %x, float %y, float %z) { +; CHECK-LABEL: @maximumnum_x_y_maximumnum_z( +; CHECK-NEXT: [[A:%.*]] = call float @llvm.maximumnum.f32(float [[X:%.*]], float [[Y:%.*]]) +; CHECK-NEXT: [[B:%.*]] = call float @llvm.maximumnum.f32(float [[A]], float [[Z:%.*]]) +; CHECK-NEXT: ret float [[B]] +; + %a = call float @llvm.maximumnum.f32(float %x, float %y) + %b = call float @llvm.maximumnum.f32(float %a, float %z) + ret float %b +} + +; maximumnum(X, INF) --> INF + +define <2 x double> @maximumnum_inf(<2 x double> %x) { +; CHECK-LABEL: @maximumnum_inf( +; CHECK-NEXT: ret <2 x double> splat (double 0x7FF0000000000000) +; + %val = call <2 x double> @llvm.maximumnum.v2f64(<2 x double> %x, <2 x double>) + ret <2 x double> %val +} + +define float @maximumnum_inf_commute(float %x) { +; CHECK-LABEL: @maximumnum_inf_commute( +; CHECK-NEXT: ret float 0x7FF0000000000000 +; + %val = call float @llvm.maximumnum.f32(float 0x7FF0000000000000, float %x) + ret float %val +} + +; negative test + +define float @maximumnum_neginf(float %x) { +; CHECK-LABEL: @maximumnum_neginf( +; CHECK-NEXT: [[VAL:%.*]] = call float @llvm.maximumnum.f32(float 0xFFF0000000000000, float [[X:%.*]]) +; CHECK-NEXT: ret float [[VAL]] +; + %val = call float @llvm.maximumnum.f32(float 0xFFF0000000000000, float %x) + ret float %val +} + +define double @maximumnum_maximumnum_minimumnum(double %x, double %y) { +; CHECK-LABEL: @maximumnum_maximumnum_minimumnum( +; CHECK-NEXT: [[MAX:%.*]] = call double @llvm.maximumnum.f64(double [[X:%.*]], double [[Y:%.*]]) +; CHECK-NEXT: ret double [[MAX]] +; + %max = call double @llvm.maximumnum.f64(double %x, double %y) + %min = call double @llvm.minimumnum.f64(double %x, double %y) + %val = call double @llvm.maximumnum.f64(double %max, double %min) + ret double %val +} + +define <2 x float> @maximumnum_minimumnum_maximumnum(<2 x float> %x, <2 x float> %y) { +; CHECK-LABEL: @maximumnum_minimumnum_maximumnum( +; CHECK-NEXT: [[MAX:%.*]] = call <2 x float> @llvm.maximumnum.v2f32(<2 x float> [[X:%.*]], <2 x float> [[Y:%.*]]) +; CHECK-NEXT: ret <2 x float> [[MAX]] +; + %max = call <2 x float> @llvm.maximumnum.v2f32(<2 x float> %x, <2 x float> %y) + %min = call <2 x float> @llvm.minimumnum.v2f32(<2 x float> %x, <2 x float> %y) + %val = call <2 x float> @llvm.maximumnum.v2f32(<2 x float> %min, <2 x float> %max) + ret <2 x float> %val +} + +define <2 x double> @maximumnum_minimumnum_minimumnum(<2 x double> %x, <2 x double> %y) { +; CHECK-LABEL: @maximumnum_minimumnum_minimumnum( +; CHECK-NEXT: [[MIN1:%.*]] = call <2 x double> @llvm.minimumnum.v2f64(<2 x double> [[X:%.*]], <2 x double> [[Y:%.*]]) +; CHECK-NEXT: [[MIN2:%.*]] = call <2 x double> @llvm.minimumnum.v2f64(<2 x double> [[X]], <2 x double> [[Y]]) +; CHECK-NEXT: [[VAL:%.*]] = call <2 x double> @llvm.maximumnum.v2f64(<2 x double> [[MIN1]], <2 x double> [[MIN2]]) +; CHECK-NEXT: ret <2 x double> [[VAL]] +; + %min1 = call <2 x double> @llvm.minimumnum.v2f64(<2 x double> %x, <2 x double> %y) + %min2 = call <2 x double> @llvm.minimumnum.v2f64(<2 x double> %x, <2 x double> %y) + %val = call <2 x double> @llvm.maximumnum.v2f64(<2 x double> %min1, <2 x double> %min2) + ret <2 x double> %val +} + +define float @maximumnum_maximumnum_maximumnum(float %x, float %y) { +; CHECK-LABEL: @maximumnum_maximumnum_maximumnum( +; CHECK-NEXT: [[MAX1:%.*]] = call float @llvm.maximumnum.f32(float [[X:%.*]], float [[Y:%.*]]) +; CHECK-NEXT: ret float [[MAX1]] +; + %max1 = call float @llvm.maximumnum.f32(float %x, float %y) + %max2 = call float @llvm.maximumnum.f32(float %x, float %y) + %val = call float @llvm.maximumnum.f32(float %max1, float %max2) + ret float %val +} + +define double @minimumnum_maximumnum_minimumnum(double %x, double %y) { +; CHECK-LABEL: @minimumnum_maximumnum_minimumnum( +; CHECK-NEXT: [[MIN:%.*]] = call double @llvm.minimumnum.f64(double [[X:%.*]], double [[Y:%.*]]) +; CHECK-NEXT: ret double [[MIN]] +; + %max = call double @llvm.maximumnum.f64(double %x, double %y) + %min = call double @llvm.minimumnum.f64(double %x, double %y) + %val = call double @llvm.minimumnum.f64(double %max, double %min) + ret double %val +} + +define float @minimumnum_minimumnum_maximumnum(float %x, float %y) { +; CHECK-LABEL: @minimumnum_minimumnum_maximumnum( +; CHECK-NEXT: [[MIN:%.*]] = call float @llvm.minimumnum.f32(float [[X:%.*]], float [[Y:%.*]]) +; CHECK-NEXT: ret float [[MIN]] +; + %max = call float @llvm.maximumnum.f32(float %x, float %y) + %min = call float @llvm.minimumnum.f32(float %x, float %y) + %val = call float @llvm.minimumnum.f32(float %min, float %max) + ret float %val +} + +define <2 x float> @minimumnum_maximumnum_maximumnum(<2 x float> %x, <2 x float> %y) { +; CHECK-LABEL: @minimumnum_maximumnum_maximumnum( +; CHECK-NEXT: [[MAX1:%.*]] = call <2 x float> @llvm.maximumnum.v2f32(<2 x float> [[X:%.*]], <2 x float> [[Y:%.*]]) +; CHECK-NEXT: [[MAX2:%.*]] = call <2 x float> @llvm.maximumnum.v2f32(<2 x float> [[X]], <2 x float> [[Y]]) +; CHECK-NEXT: [[VAL:%.*]] = call <2 x float> @llvm.minimumnum.v2f32(<2 x float> [[MAX1]], <2 x float> [[MAX2]]) +; CHECK-NEXT: ret <2 x float> [[VAL]] +; + %max1 = call <2 x float> @llvm.maximumnum.v2f32(<2 x float> %x, <2 x float> %y) + %max2 = call <2 x float> @llvm.maximumnum.v2f32(<2 x float> %x, <2 x float> %y) + %val = call <2 x float> @llvm.minimumnum.v2f32(<2 x float> %max1, <2 x float> %max2) + ret <2 x float> %val +} + +define <2 x double> @minimumnum_minimumnum_minimumnum(<2 x double> %x, <2 x double> %y) { +; CHECK-LABEL: @minimumnum_minimumnum_minimumnum( +; CHECK-NEXT: [[MIN1:%.*]] = call <2 x double> @llvm.minimumnum.v2f64(<2 x double> [[X:%.*]], <2 x double> [[Y:%.*]]) +; CHECK-NEXT: ret <2 x double> [[MIN1]] +; + %min1 = call <2 x double> @llvm.minimumnum.v2f64(<2 x double> %x, <2 x double> %y) + %min2 = call <2 x double> @llvm.minimumnum.v2f64(<2 x double> %x, <2 x double> %y) + %val = call <2 x double> @llvm.minimumnum.v2f64(<2 x double> %min1, <2 x double> %min2) + ret <2 x double> %val +} From 4c19f04c6d5ff25c6571f6061e41b063426368d4 Mon Sep 17 00:00:00 2001 From: Lewis Crawford Date: Tue, 13 May 2025 12:15:09 +0000 Subject: [PATCH 2/6] Add more vector tests + cleanup - Add tests for vectors of pairs. - Add more vector tests for and - Remove comment wording about FTZ. - Clarify behavior of fmaxnum(x, ) -> x in comments (assume snan == qnan) --- llvm/lib/Analysis/InstructionSimplify.cpp | 19 ++- .../Transforms/InstSimplify/fminmax-folds.ll | 152 ++++++++++++++++++ 2 files changed, 161 insertions(+), 10 deletions(-) diff --git a/llvm/lib/Analysis/InstructionSimplify.cpp b/llvm/lib/Analysis/InstructionSimplify.cpp index 49774bcb45585..f4dfb01a8a569 100644 --- a/llvm/lib/Analysis/InstructionSimplify.cpp +++ b/llvm/lib/Analysis/InstructionSimplify.cpp @@ -6718,9 +6718,9 @@ Value *llvm::simplifyBinaryIntrinsic(Intrinsic::ID IID, Type *ReturnType, // In several cases here, we deviate from exact IEEE 754 semantics // to enable optimizations (as allowed by the LLVM IR spec). // - // For instance, we often return one of the arguments unmodified instead of - // inserting an llvm.canonicalize to transform input sNaNs into qNaNs or to - // respect any FTZ semantics, and sometimes assume all NaN inputs are qNaNs. + // For instance, we may return one of the arguments unmodified instead of + // inserting an llvm.canonicalize to transform input sNaNs into qNaNs, + // or may assume all NaN inputs are qNaNs. // If the arguments are the same, this is a no-op. if (Op0 == Op1) @@ -6741,15 +6741,14 @@ Value *llvm::simplifyBinaryIntrinsic(Intrinsic::ID IID, Type *ReturnType, // minnum(x, qnan) -> x // maxnum(x, qnan) -> x - // minnum(x, snan) -> qnan - // maxnum(x, snan) -> qnan + // minnum(x, snan) -> qnan (or x for vectors mixing snans and qnans) + // maxnum(x, snan) -> qnan (or x for vectors mixing snans and qnans) // minimum(X, nan) -> qnan // maximum(X, nan) -> qnan - if (match(Op1, m_NaN())) { - if (PropagateNaN || (PropagateSNaN && match(Op1, m_sNaN()))) - return propagateNaN(cast(Op1)); - return Op0; - } + if (PropagateSNaN && match(Op1, m_sNaN())) + return propagateNaN(cast(Op1)); + else if (match(Op1, m_NaN())) + return PropagateNaN ? propagateNaN(cast(Op1)) : Op0; // In the following folds, inf can be replaced with the largest finite // float, if the ninf flag is set. diff --git a/llvm/test/Transforms/InstSimplify/fminmax-folds.ll b/llvm/test/Transforms/InstSimplify/fminmax-folds.ll index ae5b965ff2723..27467cf05f798 100644 --- a/llvm/test/Transforms/InstSimplify/fminmax-folds.ll +++ b/llvm/test/Transforms/InstSimplify/fminmax-folds.ll @@ -849,6 +849,38 @@ define <2 x double> @minnum_snan_op1_vec(<2 x double> %x) { ret <2 x double> %r } +define <2 x double> @maxnum_snan_qnan_op0_vec(<2 x double> %x) { +; CHECK-LABEL: @maxnum_snan_qnan_op0_vec( +; CHECK-NEXT: ret <2 x double> [[X:%.*]] +; + %r = call <2 x double> @llvm.maxnum.v2f64(<2 x double> , <2 x double> %x) + ret <2 x double> %r +} + +define <2 x double> @maxnum_snan_qnan_op1_vec(<2 x double> %x) { +; CHECK-LABEL: @maxnum_snan_qnan_op1_vec( +; CHECK-NEXT: ret <2 x double> [[X:%.*]] +; + %r = call <2 x double> @llvm.maxnum.v2f64(<2 x double> %x, <2 x double> ) + ret <2 x double> %r +} + +define <2 x double> @minnum_snan_qnan_op0_vec(<2 x double> %x) { +; CHECK-LABEL: @minnum_snan_qnan_op0_vec( +; CHECK-NEXT: ret <2 x double> [[X:%.*]] +; + %r = call <2 x double> @llvm.minnum.v2f64(<2 x double> , <2 x double> %x) + ret <2 x double> %r +} + +define <2 x double> @minnum_snan_qnan_op1_vec(<2 x double> %x) { +; CHECK-LABEL: @minnum_snan_qnan_op1_vec( +; CHECK-NEXT: ret <2 x double> [[X:%.*]] +; + %r = call <2 x double> @llvm.minnum.v2f64(<2 x double> %x, <2 x double> ) + ret <2 x double> %r +} + define float @maxnum_undef_op1(float %x) { ; CHECK-LABEL: @maxnum_undef_op1( ; CHECK-NEXT: ret float [[X:%.*]] @@ -1346,6 +1378,38 @@ define <2 x double> @minimum_snan_op1_vec(<2 x double> %x) { ret <2 x double> %r } +define <2 x double> @maximum_snan_qnan_op0_vec(<2 x double> %x) { +; CHECK-LABEL: @maximum_snan_qnan_op0_vec( +; CHECK-NEXT: ret <2 x double> +; + %r = call <2 x double> @llvm.maximum.v2f64(<2 x double> , <2 x double> %x) + ret <2 x double> %r +} + +define <2 x double> @maximum_snan_qnan_op1_vec(<2 x double> %x) { +; CHECK-LABEL: @maximum_snan_qnan_op1_vec( +; CHECK-NEXT: ret <2 x double> +; + %r = call <2 x double> @llvm.maximum.v2f64(<2 x double> %x, <2 x double> ) + ret <2 x double> %r +} + +define <2 x double> @minimum_snan_qnan_op0_vec(<2 x double> %x) { +; CHECK-LABEL: @minimum_snan_qnan_op0_vec( +; CHECK-NEXT: ret <2 x double> +; + %r = call <2 x double> @llvm.minimum.v2f64(<2 x double> , <2 x double> %x) + ret <2 x double> %r +} + +define <2 x double> @minimum_snan_qnan_op1_vec(<2 x double> %x) { +; CHECK-LABEL: @minimum_snan_qnan_op1_vec( +; CHECK-NEXT: ret <2 x double> +; + %r = call <2 x double> @llvm.minimum.v2f64(<2 x double> %x, <2 x double> ) + ret <2 x double> %r +} + define float @maximum_undef_op1(float %x) { ; CHECK-LABEL: @maximum_undef_op1( ; CHECK-NEXT: ret float [[X:%.*]] @@ -1894,6 +1958,30 @@ define <2 x double> @minimumnum_nan_op1_vec(<2 x double> %x) { ret <2 x double> %r } +define <2 x double> @maximumnum_nan_op0_vec_partial_poison(<2 x double> %x) { +; CHECK-LABEL: @maximumnum_nan_op0_vec_partial_poison( +; CHECK-NEXT: ret <2 x double> [[X:%.*]] +; + %r = call <2 x double> @llvm.maximumnum.v2f64(<2 x double> , <2 x double> %x) + ret <2 x double> %r +} + +define <2 x double> @maximumnum_nan_op1_vec_partial_poison(<2 x double> %x) { +; CHECK-LABEL: @maximumnum_nan_op1_vec_partial_poison( +; CHECK-NEXT: ret <2 x double> [[X:%.*]] +; + %r = call <2 x double> @llvm.maximumnum.v2f64(<2 x double> %x, <2 x double> ) + ret <2 x double> %r +} + +define <2 x double> @minimumnum_nan_op1_vec_partial_poison(<2 x double> %x) { +; CHECK-LABEL: @minimumnum_nan_op1_vec_partial_poison( +; CHECK-NEXT: ret <2 x double> [[X:%.*]] +; + %r = call <2 x double> @llvm.minimumnum.v2f64(<2 x double> %x, <2 x double> ) + ret <2 x double> %r +} + define double @maximumnum_snan_op0(double %x) { ; CHECK-LABEL: @maximumnum_snan_op0( ; CHECK-NEXT: ret double [[X:%.*]] @@ -1958,6 +2046,70 @@ define <2 x double> @minimumnum_snan_op1_vec(<2 x double> %x) { ret <2 x double> %r } +define <2 x double> @maximumnum_snan_op0_vec_partial_poison(<2 x double> %x) { +; CHECK-LABEL: @maximumnum_snan_op0_vec_partial_poison( +; CHECK-NEXT: ret <2 x double> [[X:%.*]] +; + %r = call <2 x double> @llvm.maximumnum.v2f64(<2 x double> , <2 x double> %x) + ret <2 x double> %r +} + +define <2 x double> @maximumnum_snan_op1_vec_partial_poison(<2 x double> %x) { +; CHECK-LABEL: @maximumnum_snan_op1_vec_partial_poison( +; CHECK-NEXT: ret <2 x double> [[X:%.*]] +; + %r = call <2 x double> @llvm.maximumnum.v2f64(<2 x double> %x, <2 x double> ) + ret <2 x double> %r +} + +define <2 x double> @minimumnum_snan_op0_vec_partial_poison(<2 x double> %x) { +; CHECK-LABEL: @minimumnum_snan_op0_vec_partial_poison( +; CHECK-NEXT: ret <2 x double> [[X:%.*]] +; + %r = call <2 x double> @llvm.minimumnum.v2f64(<2 x double> , <2 x double> %x) + ret <2 x double> %r +} + +define <2 x double> @minimumnum_snan_op1_vec_partial_poison(<2 x double> %x) { +; CHECK-LABEL: @minimumnum_snan_op1_vec_partial_poison( +; CHECK-NEXT: ret <2 x double> [[X:%.*]] +; + %r = call <2 x double> @llvm.minimumnum.v2f64(<2 x double> %x, <2 x double> ) + ret <2 x double> %r +} + +define <2 x double> @maximumnum_snan_qnan_op0_vec(<2 x double> %x) { +; CHECK-LABEL: @maximumnum_snan_qnan_op0_vec( +; CHECK-NEXT: ret <2 x double> [[X:%.*]] +; + %r = call <2 x double> @llvm.maximumnum.v2f64(<2 x double> , <2 x double> %x) + ret <2 x double> %r +} + +define <2 x double> @maximumnum_snan_qnan_op1_vec(<2 x double> %x) { +; CHECK-LABEL: @maximumnum_snan_qnan_op1_vec( +; CHECK-NEXT: ret <2 x double> [[X:%.*]] +; + %r = call <2 x double> @llvm.maximumnum.v2f64(<2 x double> %x, <2 x double> ) + ret <2 x double> %r +} + +define <2 x double> @minimumnum_snan_qnan_op0_vec(<2 x double> %x) { +; CHECK-LABEL: @minimumnum_snan_qnan_op0_vec( +; CHECK-NEXT: ret <2 x double> [[X:%.*]] +; + %r = call <2 x double> @llvm.minimumnum.v2f64(<2 x double> , <2 x double> %x) + ret <2 x double> %r +} + +define <2 x double> @minimumnum_snan_qnan_op1_vec(<2 x double> %x) { +; CHECK-LABEL: @minimumnum_snan_qnan_op1_vec( +; CHECK-NEXT: ret <2 x double> [[X:%.*]] +; + %r = call <2 x double> @llvm.minimumnum.v2f64(<2 x double> %x, <2 x double> ) + ret <2 x double> %r +} + define float @maximumnum_poison_op1(float %x) { ; CHECK-LABEL: @maximumnum_poison_op1( ; CHECK-NEXT: ret float [[X:%.*]] From bfded3715e396e23fec23ef0f61c714719e30ede Mon Sep 17 00:00:00 2001 From: Lewis Crawford Date: Tue, 13 May 2025 13:27:35 +0000 Subject: [PATCH 3/6] Add vector tests for all inf/max tests Add a vec2 variant for all the +inf/-inf/+max/-max tests for maxnum/maximum/maximumnum. --- .../Transforms/InstSimplify/fminmax-folds.ll | 504 ++++++++++++++++++ 1 file changed, 504 insertions(+) diff --git a/llvm/test/Transforms/InstSimplify/fminmax-folds.ll b/llvm/test/Transforms/InstSimplify/fminmax-folds.ll index 27467cf05f798..a33dd6e6766d7 100644 --- a/llvm/test/Transforms/InstSimplify/fminmax-folds.ll +++ b/llvm/test/Transforms/InstSimplify/fminmax-folds.ll @@ -169,6 +169,57 @@ define float @test_minimumnum_const_inf(float %x) { ret float %r } +define <2 x float> @test_minnum_const_inf_vec(<2 x float> %x) { +; CHECK-LABEL: @test_minnum_const_inf_vec( +; CHECK-NEXT: [[X:%.*]] = call <2 x float> @llvm.minnum.v2f32(<2 x float> [[X1:%.*]], <2 x float> splat (float 0x7FF0000000000000)) +; CHECK-NEXT: ret <2 x float> [[X]] +; + %r = call <2 x float> @llvm.minnum.v2f32(<2 x float> %x, <2 x float> ) + ret <2 x float> %r +} + +define <2 x float> @test_maxnum_const_inf_vec(<2 x float> %x) { +; CHECK-LABEL: @test_maxnum_const_inf_vec( +; CHECK-NEXT: ret <2 x float> splat (float 0x7FF0000000000000) +; + %r = call <2 x float> @llvm.maxnum.v2f32(<2 x float> %x, <2 x float> ) + ret <2 x float> %r +} + +define <2 x float> @test_maximum_const_inf_vec(<2 x float> %x) { +; CHECK-LABEL: @test_maximum_const_inf_vec( +; CHECK-NEXT: [[R:%.*]] = call <2 x float> @llvm.maximum.v2f32(<2 x float> [[X:%.*]], <2 x float> splat (float 0x7FF0000000000000)) +; CHECK-NEXT: ret <2 x float> [[R]] +; + %r = call <2 x float> @llvm.maximum.v2f32(<2 x float> %x, <2 x float> ) + ret <2 x float> %r +} + +define <2 x float> @test_minimum_const_inf_vec(<2 x float> %x) { +; CHECK-LABEL: @test_minimum_const_inf_vec( +; CHECK-NEXT: ret <2 x float> [[X:%.*]] +; + %r = call <2 x float> @llvm.minimum.v2f32(<2 x float> %x, <2 x float> ) + ret <2 x float> %r +} + +define <2 x float> @test_maximumnum_const_inf_vec(<2 x float> %x) { +; CHECK-LABEL: @test_maximumnum_const_inf_vec( +; CHECK-NEXT: ret <2 x float> splat (float 0x7FF0000000000000) +; + %r = call <2 x float> @llvm.maximumnum.v2f32(<2 x float> %x, <2 x float> ) + ret <2 x float> %r +} + +define <2 x float> @test_minimumnum_const_inf_vec(<2 x float> %x) { +; CHECK-LABEL: @test_minimumnum_const_inf_vec( +; CHECK-NEXT: [[X:%.*]] = call <2 x float> @llvm.minimumnum.v2f32(<2 x float> [[X1:%.*]], <2 x float> splat (float 0x7FF0000000000000)) +; CHECK-NEXT: ret <2 x float> [[X]] +; + %r = call <2 x float> @llvm.minimumnum.v2f32(<2 x float> %x, <2 x float> ) + ret <2 x float> %r +} + define float @test_minnum_const_neg_inf(float %x) { ; CHECK-LABEL: @test_minnum_const_neg_inf( ; CHECK-NEXT: ret float 0xFFF0000000000000 @@ -220,6 +271,57 @@ define float @test_minimumnum_const_neg_inf(float %x) { ret float %r } +define <2 x float> @test_minnum_const_neg_inf_vec(<2 x float> %x) { +; CHECK-LABEL: @test_minnum_const_neg_inf_vec( +; CHECK-NEXT: ret <2 x float> splat (float 0xFFF0000000000000) +; + %r = call <2 x float> @llvm.minnum.v2f32(<2 x float> %x, <2 x float> ) + ret <2 x float> %r +} + +define <2 x float> @test_maxnum_const_neg_inf_vec(<2 x float> %x) { +; CHECK-LABEL: @test_maxnum_const_neg_inf_vec( +; CHECK-NEXT: [[R:%.*]] = call <2 x float> @llvm.maxnum.v2f32(<2 x float> [[X:%.*]], <2 x float> splat (float 0xFFF0000000000000)) +; CHECK-NEXT: ret <2 x float> [[R]] +; + %r = call <2 x float> @llvm.maxnum.v2f32(<2 x float> %x, <2 x float> ) + ret <2 x float> %r +} + +define <2 x float> @test_maximum_const_neg_inf_vec(<2 x float> %x) { +; CHECK-LABEL: @test_maximum_const_neg_inf_vec( +; CHECK-NEXT: ret <2 x float> [[X:%.*]] +; + %r = call <2 x float> @llvm.maximum.v2f32(<2 x float> %x, <2 x float> ) + ret <2 x float> %r +} + +define <2 x float> @test_minimum_const_neg_inf_vec(<2 x float> %x) { +; CHECK-LABEL: @test_minimum_const_neg_inf_vec( +; CHECK-NEXT: [[X:%.*]] = call <2 x float> @llvm.minimum.v2f32(<2 x float> [[X1:%.*]], <2 x float> splat (float 0xFFF0000000000000)) +; CHECK-NEXT: ret <2 x float> [[X]] +; + %r = call <2 x float> @llvm.minimum.v2f32(<2 x float> %x, <2 x float> ) + ret <2 x float> %r +} + +define <2 x float> @test_maximumnum_const_neg_inf_vec(<2 x float> %x) { +; CHECK-LABEL: @test_maximumnum_const_neg_inf_vec( +; CHECK-NEXT: [[R:%.*]] = call <2 x float> @llvm.maximumnum.v2f32(<2 x float> [[X:%.*]], <2 x float> splat (float 0xFFF0000000000000)) +; CHECK-NEXT: ret <2 x float> [[R]] +; + %r = call <2 x float> @llvm.maximumnum.v2f32(<2 x float> %x, <2 x float> ) + ret <2 x float> %r +} + +define <2 x float> @test_minimumnum_const_neg_inf_vec(<2 x float> %x) { +; CHECK-LABEL: @test_minimumnum_const_neg_inf_vec( +; CHECK-NEXT: ret <2 x float> splat (float 0xFFF0000000000000) +; + %r = call <2 x float> @llvm.minimumnum.v2f32(<2 x float> %x, <2 x float> ) + ret <2 x float> %r +} + define float @test_minnum_const_inf_nnan(float %x) { ; CHECK-LABEL: @test_minnum_const_inf_nnan( ; CHECK-NEXT: ret float [[X:%.*]] @@ -268,6 +370,54 @@ define float @test_minimumnum_const_inf_nnan(float %x) { ret float %r } +define <2 x float> @test_minnum_const_inf_nnan_vec(<2 x float> %x) { +; CHECK-LABEL: @test_minnum_const_inf_nnan_vec( +; CHECK-NEXT: ret <2 x float> [[X:%.*]] +; + %r = call nnan <2 x float> @llvm.minnum.v2f32(<2 x float> %x, <2 x float> ) + ret <2 x float> %r +} + +define <2 x float> @test_maxnum_const_inf_nnan_vec(<2 x float> %x) { +; CHECK-LABEL: @test_maxnum_const_inf_nnan_vec( +; CHECK-NEXT: ret <2 x float> splat (float 0x7FF0000000000000) +; + %r = call nnan <2 x float> @llvm.maxnum.v2f32(<2 x float> %x, <2 x float> ) + ret <2 x float> %r +} + +define <2 x float> @test_maximum_const_inf_nnan_vec(<2 x float> %x) { +; CHECK-LABEL: @test_maximum_const_inf_nnan_vec( +; CHECK-NEXT: ret <2 x float> splat (float 0x7FF0000000000000) +; + %r = call nnan <2 x float> @llvm.maximum.v2f32(<2 x float> %x, <2 x float> ) + ret <2 x float> %r +} + +define <2 x float> @test_minimum_const_inf_nnan_vec(<2 x float> %x) { +; CHECK-LABEL: @test_minimum_const_inf_nnan_vec( +; CHECK-NEXT: ret <2 x float> [[X:%.*]] +; + %r = call nnan <2 x float> @llvm.minimum.v2f32(<2 x float> %x, <2 x float> ) + ret <2 x float> %r +} + +define <2 x float> @test_maximumnum_const_inf_nnan_vec(<2 x float> %x) { +; CHECK-LABEL: @test_maximumnum_const_inf_nnan_vec( +; CHECK-NEXT: ret <2 x float> splat (float 0x7FF0000000000000) +; + %r = call nnan <2 x float> @llvm.maximumnum.v2f32(<2 x float> %x, <2 x float> ) + ret <2 x float> %r +} + +define <2 x float> @test_minimumnum_const_inf_nnan_vec(<2 x float> %x) { +; CHECK-LABEL: @test_minimumnum_const_inf_nnan_vec( +; CHECK-NEXT: ret <2 x float> [[X:%.*]] +; + %r = call nnan <2 x float> @llvm.minimumnum.v2f32(<2 x float> %x, <2 x float> ) + ret <2 x float> %r +} + define float @test_minnum_const_inf_nnan_comm(float %x) { ; CHECK-LABEL: @test_minnum_const_inf_nnan_comm( ; CHECK-NEXT: ret float [[X:%.*]] @@ -412,6 +562,54 @@ define float @test_minimumnum_const_neg_inf_nnan(float %x) { ret float %r } +define <2 x float> @test_minnum_const_neg_inf_nnan_vec(<2 x float> %x) { +; CHECK-LABEL: @test_minnum_const_neg_inf_nnan_vec( +; CHECK-NEXT: ret <2 x float> splat (float 0xFFF0000000000000) +; + %r = call nnan <2 x float> @llvm.minnum.v2f32(<2 x float> %x, <2 x float> ) + ret <2 x float> %r +} + +define <2 x float> @test_maxnum_const_neg_inf_nnan_vec(<2 x float> %x) { +; CHECK-LABEL: @test_maxnum_const_neg_inf_nnan_vec( +; CHECK-NEXT: ret <2 x float> [[X:%.*]] +; + %r = call nnan <2 x float> @llvm.maxnum.v2f32(<2 x float> %x, <2 x float> ) + ret <2 x float> %r +} + +define <2 x float> @test_maximum_const_neg_inf_nnan_vec(<2 x float> %x) { +; CHECK-LABEL: @test_maximum_const_neg_inf_nnan_vec( +; CHECK-NEXT: ret <2 x float> [[X:%.*]] +; + %r = call nnan <2 x float> @llvm.maximum.v2f32(<2 x float> %x, <2 x float> ) + ret <2 x float> %r +} + +define <2 x float> @test_minimum_const_neg_inf_nnan_vec(<2 x float> %x) { +; CHECK-LABEL: @test_minimum_const_neg_inf_nnan_vec( +; CHECK-NEXT: ret <2 x float> splat (float 0xFFF0000000000000) +; + %r = call nnan <2 x float> @llvm.minimum.v2f32(<2 x float> %x, <2 x float> ) + ret <2 x float> %r +} + +define <2 x float> @test_maximumnum_const_neg_inf_nnan_vec(<2 x float> %x) { +; CHECK-LABEL: @test_maximumnum_const_neg_inf_nnan_vec( +; CHECK-NEXT: ret <2 x float> [[X:%.*]] +; + %r = call nnan <2 x float> @llvm.maximumnum.v2f32(<2 x float> %x, <2 x float> ) + ret <2 x float> %r +} + +define <2 x float> @test_minimumnum_const_neg_inf_nnan_vec(<2 x float> %x) { +; CHECK-LABEL: @test_minimumnum_const_neg_inf_nnan_vec( +; CHECK-NEXT: ret <2 x float> splat (float 0xFFF0000000000000) +; + %r = call nnan <2 x float> @llvm.minimumnum.v2f32(<2 x float> %x, <2 x float> ) + ret <2 x float> %r +} + define float @test_minnum_const_max(float %x) { ; CHECK-LABEL: @test_minnum_const_max( ; CHECK-NEXT: [[R:%.*]] = call float @llvm.minnum.f32(float [[X:%.*]], float 0x47EFFFFFE0000000) @@ -466,6 +664,60 @@ define float @test_minimumnum_const_max(float %x) { ret float %r } +define <2 x float> @test_minnum_const_max_vec(<2 x float> %x) { +; CHECK-LABEL: @test_minnum_const_max_vec( +; CHECK-NEXT: [[X:%.*]] = call <2 x float> @llvm.minnum.v2f32(<2 x float> [[X1:%.*]], <2 x float> splat (float 0x47EFFFFFE0000000)) +; CHECK-NEXT: ret <2 x float> [[X]] +; + %r = call <2 x float> @llvm.minnum.v2f32(<2 x float> %x, <2 x float> ) + ret <2 x float> %r +} + +define <2 x float> @test_maxnum_const_max_vec(<2 x float> %x) { +; CHECK-LABEL: @test_maxnum_const_max_vec( +; CHECK-NEXT: [[R:%.*]] = call <2 x float> @llvm.maxnum.v2f32(<2 x float> [[X:%.*]], <2 x float> splat (float 0x47EFFFFFE0000000)) +; CHECK-NEXT: ret <2 x float> [[R]] +; + %r = call <2 x float> @llvm.maxnum.v2f32(<2 x float> %x, <2 x float> ) + ret <2 x float> %r +} + +define <2 x float> @test_maximum_const_max_vec(<2 x float> %x) { +; CHECK-LABEL: @test_maximum_const_max_vec( +; CHECK-NEXT: [[R:%.*]] = call <2 x float> @llvm.maximum.v2f32(<2 x float> [[X:%.*]], <2 x float> splat (float 0x47EFFFFFE0000000)) +; CHECK-NEXT: ret <2 x float> [[R]] +; + %r = call <2 x float> @llvm.maximum.v2f32(<2 x float> %x, <2 x float> ) + ret <2 x float> %r +} + +define <2 x float> @test_minimum_const_max_vec(<2 x float> %x) { +; CHECK-LABEL: @test_minimum_const_max_vec( +; CHECK-NEXT: [[X:%.*]] = call <2 x float> @llvm.minimum.v2f32(<2 x float> [[X1:%.*]], <2 x float> splat (float 0x47EFFFFFE0000000)) +; CHECK-NEXT: ret <2 x float> [[X]] +; + %r = call <2 x float> @llvm.minimum.v2f32(<2 x float> %x, <2 x float> ) + ret <2 x float> %r +} + +define <2 x float> @test_maximumnum_const_max_vec(<2 x float> %x) { +; CHECK-LABEL: @test_maximumnum_const_max_vec( +; CHECK-NEXT: [[R:%.*]] = call <2 x float> @llvm.maximumnum.v2f32(<2 x float> [[X:%.*]], <2 x float> splat (float 0x47EFFFFFE0000000)) +; CHECK-NEXT: ret <2 x float> [[R]] +; + %r = call <2 x float> @llvm.maximumnum.v2f32(<2 x float> %x, <2 x float> ) + ret <2 x float> %r +} + +define <2 x float> @test_minimumnum_const_max_vec(<2 x float> %x) { +; CHECK-LABEL: @test_minimumnum_const_max_vec( +; CHECK-NEXT: [[X:%.*]] = call <2 x float> @llvm.minimumnum.v2f32(<2 x float> [[X1:%.*]], <2 x float> splat (float 0x47EFFFFFE0000000)) +; CHECK-NEXT: ret <2 x float> [[X]] +; + %r = call <2 x float> @llvm.minimumnum.v2f32(<2 x float> %x, <2 x float> ) + ret <2 x float> %r +} + define float @test_minnum_const_neg_max(float %x) { ; CHECK-LABEL: @test_minnum_const_neg_max( ; CHECK-NEXT: [[R:%.*]] = call float @llvm.minnum.f32(float [[X:%.*]], float 0xC7EFFFFFE0000000) @@ -520,6 +772,60 @@ define float @test_minimumnum_const_neg_max(float %x) { ret float %r } +define <2 x float> @test_minnum_const_neg_max_vec(<2 x float> %x) { +; CHECK-LABEL: @test_minnum_const_neg_max_vec( +; CHECK-NEXT: [[X:%.*]] = call <2 x float> @llvm.minnum.v2f32(<2 x float> [[X1:%.*]], <2 x float> splat (float 0xC7EFFFFFE0000000)) +; CHECK-NEXT: ret <2 x float> [[X]] +; + %r = call <2 x float> @llvm.minnum.v2f32(<2 x float> %x, <2 x float> ) + ret <2 x float> %r +} + +define <2 x float> @test_maxnum_const_neg_max_vec(<2 x float> %x) { +; CHECK-LABEL: @test_maxnum_const_neg_max_vec( +; CHECK-NEXT: [[R:%.*]] = call <2 x float> @llvm.maxnum.v2f32(<2 x float> [[X:%.*]], <2 x float> splat (float 0xC7EFFFFFE0000000)) +; CHECK-NEXT: ret <2 x float> [[R]] +; + %r = call <2 x float> @llvm.maxnum.v2f32(<2 x float> %x, <2 x float> ) + ret <2 x float> %r +} + +define <2 x float> @test_maximum_const_neg_max_vec(<2 x float> %x) { +; CHECK-LABEL: @test_maximum_const_neg_max_vec( +; CHECK-NEXT: [[R:%.*]] = call <2 x float> @llvm.maximum.v2f32(<2 x float> [[X:%.*]], <2 x float> splat (float 0xC7EFFFFFE0000000)) +; CHECK-NEXT: ret <2 x float> [[R]] +; + %r = call <2 x float> @llvm.maximum.v2f32(<2 x float> %x, <2 x float> ) + ret <2 x float> %r +} + +define <2 x float> @test_minimum_const_neg_max_vec(<2 x float> %x) { +; CHECK-LABEL: @test_minimum_const_neg_max_vec( +; CHECK-NEXT: [[X:%.*]] = call <2 x float> @llvm.minimum.v2f32(<2 x float> [[X1:%.*]], <2 x float> splat (float 0xC7EFFFFFE0000000)) +; CHECK-NEXT: ret <2 x float> [[X]] +; + %r = call <2 x float> @llvm.minimum.v2f32(<2 x float> %x, <2 x float> ) + ret <2 x float> %r +} + +define <2 x float> @test_maximumnum_const_neg_max_vec(<2 x float> %x) { +; CHECK-LABEL: @test_maximumnum_const_neg_max_vec( +; CHECK-NEXT: [[R:%.*]] = call <2 x float> @llvm.maximumnum.v2f32(<2 x float> [[X:%.*]], <2 x float> splat (float 0xC7EFFFFFE0000000)) +; CHECK-NEXT: ret <2 x float> [[R]] +; + %r = call <2 x float> @llvm.maximumnum.v2f32(<2 x float> %x, <2 x float> ) + ret <2 x float> %r +} + +define <2 x float> @test_minimumnum_const_neg_max_vec(<2 x float> %x) { +; CHECK-LABEL: @test_minimumnum_const_neg_max_vec( +; CHECK-NEXT: [[X:%.*]] = call <2 x float> @llvm.minimumnum.v2f32(<2 x float> [[X1:%.*]], <2 x float> splat (float 0xC7EFFFFFE0000000)) +; CHECK-NEXT: ret <2 x float> [[X]] +; + %r = call <2 x float> @llvm.minimumnum.v2f32(<2 x float> %x, <2 x float> ) + ret <2 x float> %r +} + define float @test_minnum_const_max_ninf(float %x) { ; CHECK-LABEL: @test_minnum_const_max_ninf( ; CHECK-NEXT: [[R:%.*]] = call ninf float @llvm.minnum.f32(float [[X:%.*]], float 0x47EFFFFFE0000000) @@ -571,6 +877,57 @@ define float @test_minimumnum_const_max_ninf(float %x) { ret float %r } +define <2 x float> @test_minnum_const_max_ninf_vec(<2 x float> %x) { +; CHECK-LABEL: @test_minnum_const_max_ninf_vec( +; CHECK-NEXT: [[X:%.*]] = call ninf <2 x float> @llvm.minnum.v2f32(<2 x float> [[X1:%.*]], <2 x float> splat (float 0x47EFFFFFE0000000)) +; CHECK-NEXT: ret <2 x float> [[X]] +; + %r = call ninf <2 x float> @llvm.minnum.v2f32(<2 x float> %x, <2 x float> ) + ret <2 x float> %r +} + +define <2 x float> @test_maxnum_const_max_ninf_vec(<2 x float> %x) { +; CHECK-LABEL: @test_maxnum_const_max_ninf_vec( +; CHECK-NEXT: ret <2 x float> splat (float 0x47EFFFFFE0000000) +; + %r = call ninf <2 x float> @llvm.maxnum.v2f32(<2 x float> %x, <2 x float> ) + ret <2 x float> %r +} + +define <2 x float> @test_maximum_const_max_ninf_vec(<2 x float> %x) { +; CHECK-LABEL: @test_maximum_const_max_ninf_vec( +; CHECK-NEXT: [[R:%.*]] = call ninf <2 x float> @llvm.maximum.v2f32(<2 x float> [[X:%.*]], <2 x float> splat (float 0x47EFFFFFE0000000)) +; CHECK-NEXT: ret <2 x float> [[R]] +; + %r = call ninf <2 x float> @llvm.maximum.v2f32(<2 x float> %x, <2 x float> ) + ret <2 x float> %r +} + +define <2 x float> @test_minimum_const_max_ninf_vec(<2 x float> %x) { +; CHECK-LABEL: @test_minimum_const_max_ninf_vec( +; CHECK-NEXT: ret <2 x float> [[X:%.*]] +; + %r = call ninf <2 x float> @llvm.minimum.v2f32(<2 x float> %x, <2 x float> ) + ret <2 x float> %r +} + +define <2 x float> @test_maximumnum_const_max_ninf_vec(<2 x float> %x) { +; CHECK-LABEL: @test_maximumnum_const_max_ninf_vec( +; CHECK-NEXT: ret <2 x float> splat (float 0x47EFFFFFE0000000) +; + %r = call ninf <2 x float> @llvm.maximumnum.v2f32(<2 x float> %x, <2 x float> ) + ret <2 x float> %r +} + +define <2 x float> @test_minimumnum_const_max_ninf_vec(<2 x float> %x) { +; CHECK-LABEL: @test_minimumnum_const_max_ninf_vec( +; CHECK-NEXT: [[X:%.*]] = call ninf <2 x float> @llvm.minimumnum.v2f32(<2 x float> [[X1:%.*]], <2 x float> splat (float 0x47EFFFFFE0000000)) +; CHECK-NEXT: ret <2 x float> [[X]] +; + %r = call ninf <2 x float> @llvm.minimumnum.v2f32(<2 x float> %x, <2 x float> ) + ret <2 x float> %r +} + define float @test_minnum_const_neg_max_ninf(float %x) { ; CHECK-LABEL: @test_minnum_const_neg_max_ninf( ; CHECK-NEXT: ret float 0xC7EFFFFFE0000000 @@ -622,6 +979,57 @@ define float @test_minimumnum_const_neg_max_ninf(float %x) { ret float %r } +define <2 x float> @test_minnum_const_neg_max_ninf_vec(<2 x float> %x) { +; CHECK-LABEL: @test_minnum_const_neg_max_ninf_vec( +; CHECK-NEXT: ret <2 x float> splat (float 0xC7EFFFFFE0000000) +; + %r = call ninf <2 x float> @llvm.minnum.v2f32(<2 x float> %x, <2 x float> ) + ret <2 x float> %r +} + +define <2 x float> @test_maxnum_const_neg_max_ninf_vec(<2 x float> %x) { +; CHECK-LABEL: @test_maxnum_const_neg_max_ninf_vec( +; CHECK-NEXT: [[R:%.*]] = call ninf <2 x float> @llvm.maxnum.v2f32(<2 x float> [[X:%.*]], <2 x float> splat (float 0xC7EFFFFFE0000000)) +; CHECK-NEXT: ret <2 x float> [[R]] +; + %r = call ninf <2 x float> @llvm.maxnum.v2f32(<2 x float> %x, <2 x float> ) + ret <2 x float> %r +} + +define <2 x float> @test_maximum_const_neg_max_ninf_vec(<2 x float> %x) { +; CHECK-LABEL: @test_maximum_const_neg_max_ninf_vec( +; CHECK-NEXT: ret <2 x float> [[X:%.*]] +; + %r = call ninf <2 x float> @llvm.maximum.v2f32(<2 x float> %x, <2 x float> ) + ret <2 x float> %r +} + +define <2 x float> @test_minimum_const_neg_max_ninf_vec(<2 x float> %x) { +; CHECK-LABEL: @test_minimum_const_neg_max_ninf_vec( +; CHECK-NEXT: [[X:%.*]] = call ninf <2 x float> @llvm.minimum.v2f32(<2 x float> [[X1:%.*]], <2 x float> splat (float 0xC7EFFFFFE0000000)) +; CHECK-NEXT: ret <2 x float> [[X]] +; + %r = call ninf <2 x float> @llvm.minimum.v2f32(<2 x float> %x, <2 x float> ) + ret <2 x float> %r +} + +define <2 x float> @test_maximumnum_const_neg_max_ninf_vec(<2 x float> %x) { +; CHECK-LABEL: @test_maximumnum_const_neg_max_ninf_vec( +; CHECK-NEXT: [[R:%.*]] = call ninf <2 x float> @llvm.maximumnum.v2f32(<2 x float> [[X:%.*]], <2 x float> splat (float 0xC7EFFFFFE0000000)) +; CHECK-NEXT: ret <2 x float> [[R]] +; + %r = call ninf <2 x float> @llvm.maximumnum.v2f32(<2 x float> %x, <2 x float> ) + ret <2 x float> %r +} + +define <2 x float> @test_minimumnum_const_neg_max_ninf_vec(<2 x float> %x) { +; CHECK-LABEL: @test_minimumnum_const_neg_max_ninf_vec( +; CHECK-NEXT: ret <2 x float> splat (float 0xC7EFFFFFE0000000) +; + %r = call ninf <2 x float> @llvm.minimumnum.v2f32(<2 x float> %x, <2 x float> ) + ret <2 x float> %r +} + define float @test_minnum_const_max_nnan_ninf(float %x) { ; CHECK-LABEL: @test_minnum_const_max_nnan_ninf( ; CHECK-NEXT: ret float [[X:%.*]] @@ -670,6 +1078,54 @@ define float @test_minimumnum_const_max_nnan_ninf(float %x) { ret float %r } +define <2 x float> @test_minnum_const_max_nnan_ninf_vec(<2 x float> %x) { +; CHECK-LABEL: @test_minnum_const_max_nnan_ninf_vec( +; CHECK-NEXT: ret <2 x float> [[X:%.*]] +; + %r = call nnan ninf <2 x float> @llvm.minnum.v2f32(<2 x float> %x, <2 x float> ) + ret <2 x float> %r +} + +define <2 x float> @test_maxnum_const_max_nnan_ninf_vec(<2 x float> %x) { +; CHECK-LABEL: @test_maxnum_const_max_nnan_ninf_vec( +; CHECK-NEXT: ret <2 x float> splat (float 0x47EFFFFFE0000000) +; + %r = call nnan ninf <2 x float> @llvm.maxnum.v2f32(<2 x float> %x, <2 x float> ) + ret <2 x float> %r +} + +define <2 x float> @test_maximum_const_max_nnan_ninf_vec(<2 x float> %x) { +; CHECK-LABEL: @test_maximum_const_max_nnan_ninf_vec( +; CHECK-NEXT: ret <2 x float> splat (float 0x47EFFFFFE0000000) +; + %r = call nnan ninf <2 x float> @llvm.maximum.v2f32(<2 x float> %x, <2 x float> ) + ret <2 x float> %r +} + +define <2 x float> @test_minimum_const_max_nnan_ninf_vec(<2 x float> %x) { +; CHECK-LABEL: @test_minimum_const_max_nnan_ninf_vec( +; CHECK-NEXT: ret <2 x float> [[X:%.*]] +; + %r = call nnan ninf <2 x float> @llvm.minimum.v2f32(<2 x float> %x, <2 x float> ) + ret <2 x float> %r +} + +define <2 x float> @test_maximumnum_const_max_nnan_ninf_vec(<2 x float> %x) { +; CHECK-LABEL: @test_maximumnum_const_max_nnan_ninf_vec( +; CHECK-NEXT: ret <2 x float> splat (float 0x47EFFFFFE0000000) +; + %r = call nnan ninf <2 x float> @llvm.maximumnum.v2f32(<2 x float> %x, <2 x float> ) + ret <2 x float> %r +} + +define <2 x float> @test_minimumnum_const_max_nnan_ninf_vec(<2 x float> %x) { +; CHECK-LABEL: @test_minimumnum_const_max_nnan_ninf_vec( +; CHECK-NEXT: ret <2 x float> [[X:%.*]] +; + %r = call nnan ninf <2 x float> @llvm.minimumnum.v2f32(<2 x float> %x, <2 x float> ) + ret <2 x float> %r +} + define float @test_minnum_const_neg_max_nnan_ninf(float %x) { ; CHECK-LABEL: @test_minnum_const_neg_max_nnan_ninf( ; CHECK-NEXT: ret float 0xC7EFFFFFE0000000 @@ -718,6 +1174,54 @@ define float @test_minimumnum_const_neg_max_nnan_ninf(float %x) { ret float %r } +define <2 x float> @test_minnum_const_neg_max_nnan_ninf_vec(<2 x float> %x) { +; CHECK-LABEL: @test_minnum_const_neg_max_nnan_ninf_vec( +; CHECK-NEXT: ret <2 x float> splat (float 0xC7EFFFFFE0000000) +; + %r = call nnan ninf <2 x float> @llvm.minnum.v2f32(<2 x float> %x, <2 x float> ) + ret <2 x float> %r +} + +define <2 x float> @test_maxnum_const_neg_max_nnan_ninf_vec(<2 x float> %x) { +; CHECK-LABEL: @test_maxnum_const_neg_max_nnan_ninf_vec( +; CHECK-NEXT: ret <2 x float> [[X:%.*]] +; + %r = call nnan ninf <2 x float> @llvm.maxnum.v2f32(<2 x float> %x, <2 x float> ) + ret <2 x float> %r +} + +define <2 x float> @test_maximum_const_neg_max_nnan_ninf_vec(<2 x float> %x) { +; CHECK-LABEL: @test_maximum_const_neg_max_nnan_ninf_vec( +; CHECK-NEXT: ret <2 x float> [[X:%.*]] +; + %r = call nnan ninf <2 x float> @llvm.maximum.v2f32(<2 x float> %x, <2 x float> ) + ret <2 x float> %r +} + +define <2 x float> @test_minimum_const_neg_max_nnan_ninf_vec(<2 x float> %x) { +; CHECK-LABEL: @test_minimum_const_neg_max_nnan_ninf_vec( +; CHECK-NEXT: ret <2 x float> splat (float 0xC7EFFFFFE0000000) +; + %r = call nnan ninf <2 x float> @llvm.minimum.v2f32(<2 x float> %x, <2 x float> ) + ret <2 x float> %r +} + +define <2 x float> @test_maximumnum_const_neg_max_nnan_ninf_vec(<2 x float> %x) { +; CHECK-LABEL: @test_maximumnum_const_neg_max_nnan_ninf_vec( +; CHECK-NEXT: ret <2 x float> [[X:%.*]] +; + %r = call nnan ninf <2 x float> @llvm.maximumnum.v2f32(<2 x float> %x, <2 x float> ) + ret <2 x float> %r +} + +define <2 x float> @test_minimumnum_const_neg_max_nnan_ninf_vec(<2 x float> %x) { +; CHECK-LABEL: @test_minimumnum_const_neg_max_nnan_ninf_vec( +; CHECK-NEXT: ret <2 x float> splat (float 0xC7EFFFFFE0000000) +; + %r = call nnan ninf <2 x float> @llvm.minimumnum.v2f32(<2 x float> %x, <2 x float> ) + ret <2 x float> %r +} + ; From the LangRef for minnum/maxnum: ; "If either operand is a qNaN, returns the other non-NaN operand. Returns NaN only if both operands are NaN or if either operand is sNaN." From fc0ec5743e83f61a0d53c0fef230c95e4f8521b6 Mon Sep 17 00:00:00 2001 From: Lewis Crawford Date: Tue, 13 May 2025 14:41:48 +0000 Subject: [PATCH 4/6] Avoid optimization for maxnum(x, ) Instead of transforming maxnum(x, ) -> x, avoid folding the maxnum away so the sNaN element can correctly be propagated as a qNaN. --- llvm/lib/Analysis/InstructionSimplify.cpp | 18 +++++++++++++----- .../Transforms/InstSimplify/fminmax-folds.ll | 12 ++++++++---- 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/llvm/lib/Analysis/InstructionSimplify.cpp b/llvm/lib/Analysis/InstructionSimplify.cpp index f4dfb01a8a569..826fa51b13c75 100644 --- a/llvm/lib/Analysis/InstructionSimplify.cpp +++ b/llvm/lib/Analysis/InstructionSimplify.cpp @@ -6741,14 +6741,22 @@ Value *llvm::simplifyBinaryIntrinsic(Intrinsic::ID IID, Type *ReturnType, // minnum(x, qnan) -> x // maxnum(x, qnan) -> x - // minnum(x, snan) -> qnan (or x for vectors mixing snans and qnans) - // maxnum(x, snan) -> qnan (or x for vectors mixing snans and qnans) + // minnum(x, snan) -> qnan + // maxnum(x, snan) -> qnan // minimum(X, nan) -> qnan // maximum(X, nan) -> qnan - if (PropagateSNaN && match(Op1, m_sNaN())) + if (PropagateSNaN && match(Op1, m_sNaN())) { return propagateNaN(cast(Op1)); - else if (match(Op1, m_NaN())) - return PropagateNaN ? propagateNaN(cast(Op1)) : Op0; + } else if (match(Op1, m_NaN())) { + if (PropagateNaN) + return propagateNaN(cast(Op1)); + // In cases like mixed vectors, avoid the optimization to + // allow correct sNaN propagation where necessary. + else if (PropagateSNaN && !match(Op1, m_qNaN())) + break; + else + return Op0; + } // In the following folds, inf can be replaced with the largest finite // float, if the ninf flag is set. diff --git a/llvm/test/Transforms/InstSimplify/fminmax-folds.ll b/llvm/test/Transforms/InstSimplify/fminmax-folds.ll index a33dd6e6766d7..db7bf06873036 100644 --- a/llvm/test/Transforms/InstSimplify/fminmax-folds.ll +++ b/llvm/test/Transforms/InstSimplify/fminmax-folds.ll @@ -1355,7 +1355,8 @@ define <2 x double> @minnum_snan_op1_vec(<2 x double> %x) { define <2 x double> @maxnum_snan_qnan_op0_vec(<2 x double> %x) { ; CHECK-LABEL: @maxnum_snan_qnan_op0_vec( -; CHECK-NEXT: ret <2 x double> [[X:%.*]] +; CHECK-NEXT: [[X:%.*]] = call <2 x double> @llvm.maxnum.v2f64(<2 x double> , <2 x double> [[X1:%.*]]) +; CHECK-NEXT: ret <2 x double> [[X]] ; %r = call <2 x double> @llvm.maxnum.v2f64(<2 x double> , <2 x double> %x) ret <2 x double> %r @@ -1363,7 +1364,8 @@ define <2 x double> @maxnum_snan_qnan_op0_vec(<2 x double> %x) { define <2 x double> @maxnum_snan_qnan_op1_vec(<2 x double> %x) { ; CHECK-LABEL: @maxnum_snan_qnan_op1_vec( -; CHECK-NEXT: ret <2 x double> [[X:%.*]] +; CHECK-NEXT: [[X:%.*]] = call <2 x double> @llvm.maxnum.v2f64(<2 x double> [[X1:%.*]], <2 x double> ) +; CHECK-NEXT: ret <2 x double> [[X]] ; %r = call <2 x double> @llvm.maxnum.v2f64(<2 x double> %x, <2 x double> ) ret <2 x double> %r @@ -1371,7 +1373,8 @@ define <2 x double> @maxnum_snan_qnan_op1_vec(<2 x double> %x) { define <2 x double> @minnum_snan_qnan_op0_vec(<2 x double> %x) { ; CHECK-LABEL: @minnum_snan_qnan_op0_vec( -; CHECK-NEXT: ret <2 x double> [[X:%.*]] +; CHECK-NEXT: [[X:%.*]] = call <2 x double> @llvm.minnum.v2f64(<2 x double> , <2 x double> [[X1:%.*]]) +; CHECK-NEXT: ret <2 x double> [[X]] ; %r = call <2 x double> @llvm.minnum.v2f64(<2 x double> , <2 x double> %x) ret <2 x double> %r @@ -1379,7 +1382,8 @@ define <2 x double> @minnum_snan_qnan_op0_vec(<2 x double> %x) { define <2 x double> @minnum_snan_qnan_op1_vec(<2 x double> %x) { ; CHECK-LABEL: @minnum_snan_qnan_op1_vec( -; CHECK-NEXT: ret <2 x double> [[X:%.*]] +; CHECK-NEXT: [[X:%.*]] = call <2 x double> @llvm.minnum.v2f64(<2 x double> [[X1:%.*]], <2 x double> ) +; CHECK-NEXT: ret <2 x double> [[X]] ; %r = call <2 x double> @llvm.minnum.v2f64(<2 x double> %x, <2 x double> ) ret <2 x double> %r From 88fe0b11eb0faae83297e1eb0097642cbf072a90 Mon Sep 17 00:00:00 2001 From: Lewis Crawford Date: Tue, 13 May 2025 15:02:45 +0000 Subject: [PATCH 5/6] Update failing AMDGPU tests Update some failing AMDGPU tests using maxnum's updated sNaN behaviour and maximumnum's new set of optimizations. --- .../test/CodeGen/AMDGPU/fcanonicalize-elimination.ll | 6 ++---- llvm/test/CodeGen/AMDGPU/fneg-combines.new.ll | 12 ++++-------- 2 files changed, 6 insertions(+), 12 deletions(-) diff --git a/llvm/test/CodeGen/AMDGPU/fcanonicalize-elimination.ll b/llvm/test/CodeGen/AMDGPU/fcanonicalize-elimination.ll index ab476dd96c707..11e510df2d147 100644 --- a/llvm/test/CodeGen/AMDGPU/fcanonicalize-elimination.ll +++ b/llvm/test/CodeGen/AMDGPU/fcanonicalize-elimination.ll @@ -497,12 +497,10 @@ define amdgpu_kernel void @test_fold_canonicalize_minnum_value_f32(ptr addrspace ret void } -; FIXME: Should there be more checks here? minnum with NaN operand is simplified away. +; FIXME: Should there be more checks here? minnum with sNaN operand is simplified to qNaN. ; GCN-LABEL: test_fold_canonicalize_sNaN_value_f32: -; GCN: {{flat|global}}_load_dword [[LOAD:v[0-9]+]] -; VI: v_mul_f32_e32 v{{[0-9]+}}, 1.0, [[LOAD]] -; GFX9: v_max_f32_e32 v{{[0-9]+}}, [[LOAD]], [[LOAD]] +; GCN: v_mov_b32_e32 v{{.+}}, 0x7fc00000 define amdgpu_kernel void @test_fold_canonicalize_sNaN_value_f32(ptr addrspace(1) %arg) { %id = tail call i32 @llvm.amdgcn.workitem.id.x() %gep = getelementptr inbounds float, ptr addrspace(1) %arg, i32 %id diff --git a/llvm/test/CodeGen/AMDGPU/fneg-combines.new.ll b/llvm/test/CodeGen/AMDGPU/fneg-combines.new.ll index 46da9d33639b6..e008ef44cd072 100644 --- a/llvm/test/CodeGen/AMDGPU/fneg-combines.new.ll +++ b/llvm/test/CodeGen/AMDGPU/fneg-combines.new.ll @@ -2032,8 +2032,7 @@ define float @v_fneg_self_minimumnum_f32_ieee(float %a) #0 { ; GCN-LABEL: v_fneg_self_minimumnum_f32_ieee: ; GCN: ; %bb.0: ; GCN-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0) -; GCN-NEXT: v_mul_f32_e32 v0, -1.0, v0 -; GCN-NEXT: v_max_f32_e32 v0, v0, v0 +; GCN-NEXT: v_xor_b32_e32 v0, 0x80000000, v0 ; GCN-NEXT: s_setpc_b64 s[30:31] %min = call float @llvm.minimumnum.f32(float %a, float %a) %min.fneg = fneg float %min @@ -2044,8 +2043,7 @@ define float @v_fneg_self_minimumnum_f32_no_ieee(float %a) #4 { ; GCN-LABEL: v_fneg_self_minimumnum_f32_no_ieee: ; GCN: ; %bb.0: ; GCN-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0) -; GCN-NEXT: v_mul_f32_e32 v0, -1.0, v0 -; GCN-NEXT: v_max_f32_e32 v0, v0, v0 +; GCN-NEXT: v_xor_b32_e32 v0, 0x80000000, v0 ; GCN-NEXT: s_setpc_b64 s[30:31] %min = call float @llvm.minimumnum.f32(float %a, float %a) %min.fneg = fneg float %min @@ -2377,8 +2375,7 @@ define float @v_fneg_self_maximumnum_f32_ieee(float %a) #0 { ; GCN-LABEL: v_fneg_self_maximumnum_f32_ieee: ; GCN: ; %bb.0: ; GCN-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0) -; GCN-NEXT: v_mul_f32_e32 v0, -1.0, v0 -; GCN-NEXT: v_min_f32_e32 v0, v0, v0 +; GCN-NEXT: v_xor_b32_e32 v0, 0x80000000, v0 ; GCN-NEXT: s_setpc_b64 s[30:31] %max = call float @llvm.maximumnum.f32(float %a, float %a) %max.fneg = fneg float %max @@ -2389,8 +2386,7 @@ define float @v_fneg_self_maximumnum_f32_no_ieee(float %a) #4 { ; GCN-LABEL: v_fneg_self_maximumnum_f32_no_ieee: ; GCN: ; %bb.0: ; GCN-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0) -; GCN-NEXT: v_mul_f32_e32 v0, -1.0, v0 -; GCN-NEXT: v_min_f32_e32 v0, v0, v0 +; GCN-NEXT: v_xor_b32_e32 v0, 0x80000000, v0 ; GCN-NEXT: s_setpc_b64 s[30:31] %max = call float @llvm.maximumnum.f32(float %a, float %a) %max.fneg = fneg float %max From 995a1a31e47b6962e7b12ffba950ebda54066ff2 Mon Sep 17 00:00:00 2001 From: Lewis Crawford Date: Thu, 15 May 2025 18:00:13 +0000 Subject: [PATCH 6/6] Tidy up if/else chain --- llvm/lib/Analysis/InstructionSimplify.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/llvm/lib/Analysis/InstructionSimplify.cpp b/llvm/lib/Analysis/InstructionSimplify.cpp index 826fa51b13c75..d6756cf45c68e 100644 --- a/llvm/lib/Analysis/InstructionSimplify.cpp +++ b/llvm/lib/Analysis/InstructionSimplify.cpp @@ -6745,9 +6745,9 @@ Value *llvm::simplifyBinaryIntrinsic(Intrinsic::ID IID, Type *ReturnType, // maxnum(x, snan) -> qnan // minimum(X, nan) -> qnan // maximum(X, nan) -> qnan - if (PropagateSNaN && match(Op1, m_sNaN())) { + if (PropagateSNaN && match(Op1, m_sNaN())) return propagateNaN(cast(Op1)); - } else if (match(Op1, m_NaN())) { + if (match(Op1, m_NaN())) { if (PropagateNaN) return propagateNaN(cast(Op1)); // In cases like mixed vectors, avoid the optimization to