Skip to content

Commit 21082fc

Browse files
committed
simplifyBinaryIntrinsic: Return nan if snan is passed maxnum/minnum
Fixes: #138303
1 parent 0bbf2ea commit 21082fc

File tree

4 files changed

+77
-6
lines changed

4 files changed

+77
-6
lines changed

llvm/include/llvm/IR/PatternMatch.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -707,9 +707,17 @@ m_SpecificInt_ICMP(ICmpInst::Predicate Predicate, const APInt &Threshold) {
707707
struct is_nan {
708708
bool isValue(const APFloat &C) const { return C.isNaN(); }
709709
};
710+
struct is_snan {
711+
bool isValue(const APFloat &C) const { return C.isSignaling(); }
712+
};
713+
struct is_qnan {
714+
bool isValue(const APFloat &C) const { return C.isNaN() && !C.isSignaling(); }
715+
};
710716
/// Match an arbitrary NaN constant. This includes quiet and signalling nans.
711717
/// For vectors, this includes constants with undefined elements.
712718
inline cstfp_pred_ty<is_nan> m_NaN() { return cstfp_pred_ty<is_nan>(); }
719+
inline cstfp_pred_ty<is_snan> m_SNaN() { return cstfp_pred_ty<is_snan>(); }
720+
inline cstfp_pred_ty<is_qnan> m_QNaN() { return cstfp_pred_ty<is_qnan>(); }
713721

714722
struct is_nonnan {
715723
bool isValue(const APFloat &C) const { return !C.isNaN(); }

llvm/lib/Analysis/InstructionSimplify.cpp

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6735,12 +6735,16 @@ Value *llvm::simplifyBinaryIntrinsic(Intrinsic::ID IID, Type *ReturnType,
67356735
bool PropagateNaN = IID == Intrinsic::minimum || IID == Intrinsic::maximum;
67366736
bool IsMin = IID == Intrinsic::minimum || IID == Intrinsic::minnum;
67376737

6738-
// minnum(X, nan) -> X
6739-
// maxnum(X, nan) -> X
6738+
// minnum(X, qnan) -> X
6739+
// maxnum(X, qnan) -> X
6740+
// minnum(X, snan) -> nan
6741+
// maxnum(X, snan) -> nan
67406742
// minimum(X, nan) -> nan
67416743
// maximum(X, nan) -> nan
6742-
if (match(Op1, m_NaN()))
6744+
if (match(Op1, m_QNaN()))
67436745
return PropagateNaN ? propagateNaN(cast<Constant>(Op1)) : Op0;
6746+
else if (match(Op1, m_SNaN()))
6747+
return propagateNaN(cast<Constant>(Op1));
67446748

67456749
// In the following folds, inf can be replaced with the largest finite
67466750
// float, if the ninf flag is set.

llvm/test/CodeGen/AMDGPU/fcanonicalize-elimination.ll

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -500,9 +500,7 @@ define amdgpu_kernel void @test_fold_canonicalize_minnum_value_f32(ptr addrspace
500500
; FIXME: Should there be more checks here? minnum with NaN operand is simplified away.
501501

502502
; GCN-LABEL: test_fold_canonicalize_sNaN_value_f32:
503-
; GCN: {{flat|global}}_load_dword [[LOAD:v[0-9]+]]
504-
; VI: v_mul_f32_e32 v{{[0-9]+}}, 1.0, [[LOAD]]
505-
; GFX9: v_max_f32_e32 v{{[0-9]+}}, [[LOAD]], [[LOAD]]
503+
; GCN: v_mov_b32_e32 v{{[0-9]+}}, 0x7fc00000
506504
define amdgpu_kernel void @test_fold_canonicalize_sNaN_value_f32(ptr addrspace(1) %arg) {
507505
%id = tail call i32 @llvm.amdgcn.workitem.id.x()
508506
%gep = getelementptr inbounds float, ptr addrspace(1) %arg, i32 %id

llvm/test/Transforms/EarlyCSE/commute.ll

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -830,6 +830,67 @@ define float @maxnum(float %a, float %b) {
830830
ret float %r
831831
}
832832

833+
define float @maxnum_const_snan(float %x) {
834+
; CHECK-LABEL: @maxnum_const_snan(
835+
; CHECK-NEXT: ret float 0x7FFC000000000000
836+
;
837+
%r = call float @llvm.minnum.f32(float %x, float 0x7FF4000000000000)
838+
ret float %r
839+
}
840+
841+
define double @minnum_const_snan(double %x) {
842+
; CHECK-LABEL: @minnum_const_snan(
843+
; CHECK-NEXT: ret double 0x7FFC000000000000
844+
;
845+
%r = call double @llvm.minnum.f64(double %x, double 0x7FF4000000000000)
846+
ret double %r
847+
}
848+
849+
define float @maxnum_const_qnan(float %x) {
850+
; CHECK-LABEL: @maxnum_const_qnan(
851+
; CHECK-NEXT: ret float [[X:%.*]]
852+
;
853+
%r = call float @llvm.minnum.f32(float %x, float 0x7FF8000000000000)
854+
ret float %r
855+
}
856+
857+
define double @minnum_const_qnan(double %x) {
858+
; CHECK-LABEL: @minnum_const_qnan(
859+
; CHECK-NEXT: ret double [[X:%.*]]
860+
;
861+
%r = call double @llvm.minnum.f64(double %x, double 0x7FF8000000000000)
862+
ret double %r
863+
}
864+
865+
define <2 x float> @maxnum_const_snan_v2f32(<2 x float> %a) {
866+
; CHECK-LABEL: @maxnum_const_snan_v2f32(
867+
; CHECK-NEXT: entry:
868+
; CHECK-NEXT: ret <2 x float> splat (float 0x7FFC000000000000)
869+
;
870+
entry:
871+
%r = tail call <2 x float> @llvm.maxnum.v2f32(<2 x float> %a, <2 x float> <float 0x7FF4000000000000, float 0x7FF4000000000000>)
872+
ret <2 x float> %r
873+
}
874+
define <2 x float> @maxnum_const_qnan_v2f32(<2 x float> %a) {
875+
; CHECK-LABEL: @maxnum_const_qnan_v2f32(
876+
; CHECK-NEXT: entry:
877+
; CHECK-NEXT: ret <2 x float> [[A:%.*]]
878+
;
879+
entry:
880+
%r = tail call <2 x float> @llvm.maxnum.v2f32(<2 x float> %a, <2 x float> <float 0x7FF8000000000000, float 0x7FF8000000000000>)
881+
ret <2 x float> %r
882+
}
883+
define <2 x float> @maxnum_const_mixednan_v2f32(<2 x float> %a) {
884+
; CHECK-LABEL: @maxnum_const_mixednan_v2f32(
885+
; CHECK-NEXT: entry:
886+
; CHECK-NEXT: [[R:%.*]] = tail call <2 x float> @llvm.maxnum.v2f32(<2 x float> [[A:%.*]], <2 x float> <float 0x7FF8000000000000, float 0x7FF4000000000000>)
887+
; CHECK-NEXT: ret <2 x float> [[R]]
888+
;
889+
entry:
890+
%r = tail call <2 x float> @llvm.maxnum.v2f32(<2 x float> %a, <2 x float> <float 0x7FF8000000000000, float 0x7FF4000000000000>)
891+
ret <2 x float> %r
892+
}
893+
833894
define <2 x float> @minnum(<2 x float> %a, <2 x float> %b) {
834895
; CHECK-LABEL: @minnum(
835896
; CHECK-NEXT: [[X:%.*]] = call fast <2 x float> @llvm.minnum.v2f32(<2 x float> [[A:%.*]], <2 x float> [[B:%.*]])

0 commit comments

Comments
 (0)