diff --git a/llvm/include/llvm/IR/PatternMatch.h b/llvm/include/llvm/IR/PatternMatch.h index 2cb78904dd799..3b8acf7686d59 100644 --- a/llvm/include/llvm/IR/PatternMatch.h +++ b/llvm/include/llvm/IR/PatternMatch.h @@ -707,9 +707,17 @@ 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(); } +inline cstfp_pred_ty m_SNaN() { return cstfp_pred_ty(); } +inline cstfp_pred_ty m_QNaN() { 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 7bff13d59528c..67e00add82810 100644 --- a/llvm/lib/Analysis/InstructionSimplify.cpp +++ b/llvm/lib/Analysis/InstructionSimplify.cpp @@ -6735,12 +6735,16 @@ Value *llvm::simplifyBinaryIntrinsic(Intrinsic::ID IID, Type *ReturnType, bool PropagateNaN = IID == Intrinsic::minimum || IID == Intrinsic::maximum; bool IsMin = IID == Intrinsic::minimum || IID == Intrinsic::minnum; - // minnum(X, nan) -> X - // maxnum(X, nan) -> X + // minnum(X, qnan) -> X + // maxnum(X, qnan) -> X + // minnum(X, snan) -> nan + // maxnum(X, snan) -> nan // minimum(X, nan) -> nan // maximum(X, nan) -> nan - if (match(Op1, m_NaN())) + if (match(Op1, m_QNaN())) return PropagateNaN ? propagateNaN(cast(Op1)) : Op0; + else if (match(Op1, m_SNaN())) + return propagateNaN(cast(Op1)); // In the following folds, inf can be replaced with the largest finite // float, if the ninf flag is set. diff --git a/llvm/test/CodeGen/AMDGPU/fcanonicalize-elimination.ll b/llvm/test/CodeGen/AMDGPU/fcanonicalize-elimination.ll index ab51693198a30..4a7d0efd46497 100644 --- a/llvm/test/CodeGen/AMDGPU/fcanonicalize-elimination.ll +++ b/llvm/test/CodeGen/AMDGPU/fcanonicalize-elimination.ll @@ -500,9 +500,7 @@ define amdgpu_kernel void @test_fold_canonicalize_minnum_value_f32(ptr addrspace ; FIXME: Should there be more checks here? minnum with NaN operand is simplified away. ; 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{{[0-9]+}}, 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/Transforms/EarlyCSE/commute.ll b/llvm/test/Transforms/EarlyCSE/commute.ll index edafeccd3c8cc..62fae0f544812 100644 --- a/llvm/test/Transforms/EarlyCSE/commute.ll +++ b/llvm/test/Transforms/EarlyCSE/commute.ll @@ -830,6 +830,67 @@ define float @maxnum(float %a, float %b) { ret float %r } +define float @maxnum_const_snan(float %x) { +; CHECK-LABEL: @maxnum_const_snan( +; CHECK-NEXT: ret float 0x7FFC000000000000 +; + %r = call float @llvm.minnum.f32(float %x, float 0x7FF4000000000000) + ret float %r +} + +define double @minnum_const_snan(double %x) { +; CHECK-LABEL: @minnum_const_snan( +; CHECK-NEXT: ret double 0x7FFC000000000000 +; + %r = call double @llvm.minnum.f64(double %x, double 0x7FF4000000000000) + ret double %r +} + +define float @maxnum_const_qnan(float %x) { +; CHECK-LABEL: @maxnum_const_qnan( +; CHECK-NEXT: ret float [[X:%.*]] +; + %r = call float @llvm.minnum.f32(float %x, float 0x7FF8000000000000) + ret float %r +} + +define double @minnum_const_qnan(double %x) { +; CHECK-LABEL: @minnum_const_qnan( +; CHECK-NEXT: ret double [[X:%.*]] +; + %r = call double @llvm.minnum.f64(double %x, double 0x7FF8000000000000) + ret double %r +} + +define <2 x float> @maxnum_const_snan_v2f32(<2 x float> %a) { +; CHECK-LABEL: @maxnum_const_snan_v2f32( +; CHECK-NEXT: entry: +; CHECK-NEXT: ret <2 x float> splat (float 0x7FFC000000000000) +; +entry: + %r = tail call <2 x float> @llvm.maxnum.v2f32(<2 x float> %a, <2 x float> ) + ret <2 x float> %r +} +define <2 x float> @maxnum_const_qnan_v2f32(<2 x float> %a) { +; CHECK-LABEL: @maxnum_const_qnan_v2f32( +; CHECK-NEXT: entry: +; CHECK-NEXT: ret <2 x float> [[A:%.*]] +; +entry: + %r = tail call <2 x float> @llvm.maxnum.v2f32(<2 x float> %a, <2 x float> ) + ret <2 x float> %r +} +define <2 x float> @maxnum_const_mixednan_v2f32(<2 x float> %a) { +; CHECK-LABEL: @maxnum_const_mixednan_v2f32( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[R:%.*]] = tail call <2 x float> @llvm.maxnum.v2f32(<2 x float> [[A:%.*]], <2 x float> ) +; CHECK-NEXT: ret <2 x float> [[R]] +; +entry: + %r = tail call <2 x float> @llvm.maxnum.v2f32(<2 x float> %a, <2 x float> ) + ret <2 x float> %r +} + define <2 x float> @minnum(<2 x float> %a, <2 x float> %b) { ; CHECK-LABEL: @minnum( ; CHECK-NEXT: [[X:%.*]] = call fast <2 x float> @llvm.minnum.v2f32(<2 x float> [[A:%.*]], <2 x float> [[B:%.*]])