Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 36 additions & 15 deletions llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19340,8 +19340,10 @@ SDValue DAGCombiner::visitFMinMax(SDNode *N) {
EVT VT = N->getValueType(0);
const SDNodeFlags Flags = N->getFlags();
unsigned Opc = N->getOpcode();
bool PropagatesNaN = Opc == ISD::FMINIMUM || Opc == ISD::FMAXIMUM;
bool IsMin = Opc == ISD::FMINNUM || Opc == ISD::FMINIMUM;
bool PropAllNaNsToQNaNs = Opc == ISD::FMINIMUM || Opc == ISD::FMAXIMUM;
bool PropOnlySNaNsToQNaNs = Opc == ISD::FMINNUM || Opc == ISD::FMAXNUM;
bool IsMin =
Opc == ISD::FMINNUM || Opc == ISD::FMINIMUM || Opc == ISD::FMINIMUMNUM;
SelectionDAG::FlagInserter FlagsInserter(DAG, N);

// Constant fold.
Expand All @@ -19356,34 +19358,53 @@ SDValue DAGCombiner::visitFMinMax(SDNode *N) {
if (const ConstantFPSDNode *N1CFP = isConstOrConstSplatFP(N1)) {
const APFloat &AF = N1CFP->getValueAPF();

// minnum(X, nan) -> X
// maxnum(X, nan) -> X
// minimum(X, nan) -> nan
// maximum(X, nan) -> nan
if (AF.isNaN())
return PropagatesNaN ? N->getOperand(1) : N->getOperand(0);
// minnum(X, qnan) -> X
// maxnum(X, qnan) -> X
// minnum(X, snan) -> qnan
// maxnum(X, snan) -> qnan
// minimum(X, nan) -> qnan
// maximum(X, nan) -> qnan
// minimumnum(X, nan) -> X
// maximumnum(X, nan) -> X
if (AF.isNaN()) {
if (PropAllNaNsToQNaNs || (AF.isSignaling() && PropOnlySNaNsToQNaNs)) {
if (AF.isSignaling())
return DAG.getConstantFP(AF.makeQuiet(), SDLoc(N), VT);
return N->getOperand(1);
}
return N->getOperand(0);
}

// In the following folds, inf can be replaced with the largest finite
// float, if the ninf flag is set.
if (AF.isInfinity() || (Flags.hasNoInfs() && AF.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
if (IsMin == AF.isNegative() && (!PropagatesNaN || Flags.hasNoNaNs()))
// minimumnum(X, -inf) -> -inf
// maximumnum(X, +inf) -> +inf
if (IsMin == AF.isNegative() &&
(!PropAllNaNsToQNaNs || Flags.hasNoNaNs()))
return N->getOperand(1);

// minnum(X, +inf) -> X if nnan
// maxnum(X, -inf) -> X if nnan
// minimum(X, +inf) -> X
// maximum(X, -inf) -> X
if (IsMin != AF.isNegative() && (PropagatesNaN || Flags.hasNoNaNs()))
// minimum(X, +inf) -> X (ignoring quieting of sNaNs)
// maximum(X, -inf) -> X (ignoring quieting of sNaNs)
// minimumnum(X, +inf) -> X if nnan
// maximumnum(X, -inf) -> X if nnan
if (IsMin != AF.isNegative() && (PropAllNaNsToQNaNs || Flags.hasNoNaNs()))
return N->getOperand(0);
}
}

// There are no VECREDUCE variants of FMINIMUMNUM or FMAXIMUMNUM
if (Opc == ISD::FMINIMUMNUM || Opc == ISD::FMAXIMUMNUM)
return SDValue();

if (SDValue SD = reassociateReduction(
PropagatesNaN
PropAllNaNsToQNaNs
? (IsMin ? ISD::VECREDUCE_FMINIMUM : ISD::VECREDUCE_FMAXIMUM)
: (IsMin ? ISD::VECREDUCE_FMIN : ISD::VECREDUCE_FMAX),
Opc, SDLoc(N), VT, N0, N1, Flags))
Expand Down
46 changes: 41 additions & 5 deletions llvm/test/CodeGen/X86/fmaxnum.ll
Original file line number Diff line number Diff line change
Expand Up @@ -645,11 +645,47 @@ define float @test_maxnum_const_op2(float %x) {
ret float %r
}

define float @test_maxnum_const_nan(float %x) {
; CHECK-LABEL: test_maxnum_const_nan:
; CHECK: # %bb.0:
; CHECK-NEXT: retq
%r = call float @llvm.maxnum.f32(float %x, float 0x7fff000000000000)
define float @test_maxnum_const_nan(float %x, float %y) {
; SSE-LABEL: test_maxnum_const_nan:
; SSE: # %bb.0:
; SSE-NEXT: movaps %xmm1, %xmm0
; SSE-NEXT: retq
;
; AVX-LABEL: test_maxnum_const_nan:
; AVX: # %bb.0:
; AVX-NEXT: vmovaps %xmm1, %xmm0
; AVX-NEXT: retq
%r = call float @llvm.maxnum.f32(float %y, float 0x7fff000000000000)
ret float %r
}

; nnan maxnum(Y, -inf) -> Y
define float @test_maxnum_neg_inf_nnan(float %x, float %y) nounwind {
; SSE-LABEL: test_maxnum_neg_inf_nnan:
; SSE: # %bb.0:
; SSE-NEXT: movaps %xmm1, %xmm0
; SSE-NEXT: retq
;
; AVX-LABEL: test_maxnum_neg_inf_nnan:
; AVX: # %bb.0:
; AVX-NEXT: vmovaps %xmm1, %xmm0
; AVX-NEXT: retq
%r = call nnan float @llvm.maxnum.f32(float %y, float 0xfff0000000000000)
ret float %r
}

; Test SNaN quieting
define float @test_maxnum_snan(float %x) {
; SSE-LABEL: test_maxnum_snan:
; SSE: # %bb.0:
; SSE-NEXT: movss {{.*#+}} xmm0 = [NaN,0.0E+0,0.0E+0,0.0E+0]
; SSE-NEXT: retq
;
; AVX-LABEL: test_maxnum_snan:
; AVX: # %bb.0:
; AVX-NEXT: vmovss {{.*#+}} xmm0 = [NaN,0.0E+0,0.0E+0,0.0E+0]
; AVX-NEXT: retq
%r = call float @llvm.maxnum.f32(float 0x7ff4000000000000, float %x)
ret float %r
}

Expand Down
99 changes: 99 additions & 0 deletions llvm/test/CodeGen/X86/fminimum-fmaximum.ll
Original file line number Diff line number Diff line change
Expand Up @@ -2649,3 +2649,102 @@ define <4 x bfloat> @test_fmaximum_v4bf16(<4 x bfloat> %x, <4 x bfloat> %y) {
%r = call <4 x bfloat> @llvm.maximum.v4bf16(<4 x bfloat> %x, <4 x bfloat> %y)
ret <4 x bfloat> %r
}

; nnan minimum(Y, +inf) -> Y
define float @test_fminimum_inf_nnan(float %x, float %y) nounwind {
; SSE2-LABEL: test_fminimum_inf_nnan:
; SSE2: # %bb.0:
; SSE2-NEXT: movaps %xmm1, %xmm0
; SSE2-NEXT: retq
;
; AVX-LABEL: test_fminimum_inf_nnan:
; AVX: # %bb.0:
; AVX-NEXT: vmovaps %xmm1, %xmm0
; AVX-NEXT: retq
;
; AVX10_2-LABEL: test_fminimum_inf_nnan:
; AVX10_2: # %bb.0:
; AVX10_2-NEXT: vmovaps %xmm1, %xmm0
; AVX10_2-NEXT: retq
;
; X86-LABEL: test_fminimum_inf_nnan:
; X86: # %bb.0:
; X86-NEXT: flds {{[0-9]+}}(%esp)
; X86-NEXT: retl
%1 = call nnan float @llvm.minimum.f32(float %y, float 0x7ff0000000000000)
ret float %1
}

; nnan maximum(Y, -inf) -> Y
define float @test_fmaximum_neg_inf_nnan(float %x, float %y) nounwind {
; SSE2-LABEL: test_fmaximum_neg_inf_nnan:
; SSE2: # %bb.0:
; SSE2-NEXT: movaps %xmm1, %xmm0
; SSE2-NEXT: retq
;
; AVX-LABEL: test_fmaximum_neg_inf_nnan:
; AVX: # %bb.0:
; AVX-NEXT: vmovaps %xmm1, %xmm0
; AVX-NEXT: retq
;
; AVX10_2-LABEL: test_fmaximum_neg_inf_nnan:
; AVX10_2: # %bb.0:
; AVX10_2-NEXT: vmovaps %xmm1, %xmm0
; AVX10_2-NEXT: retq
;
; X86-LABEL: test_fmaximum_neg_inf_nnan:
; X86: # %bb.0:
; X86-NEXT: flds {{[0-9]+}}(%esp)
; X86-NEXT: retl
%1 = call nnan float @llvm.maximum.f32(float %y, float 0xfff0000000000000)
ret float %1
}

; Test SNaN quieting
define float @test_fmaximum_snan(float %x) {
; SSE2-LABEL: test_fmaximum_snan:
; SSE2: # %bb.0:
; SSE2-NEXT: movss {{.*#+}} xmm0 = [NaN,0.0E+0,0.0E+0,0.0E+0]
; SSE2-NEXT: retq
;
; AVX-LABEL: test_fmaximum_snan:
; AVX: # %bb.0:
; AVX-NEXT: vmovss {{.*#+}} xmm0 = [NaN,0.0E+0,0.0E+0,0.0E+0]
; AVX-NEXT: retq
;
; AVX10_2-LABEL: test_fmaximum_snan:
; AVX10_2: # %bb.0:
; AVX10_2-NEXT: vmovss {{.*#+}} xmm0 = [NaN,0.0E+0,0.0E+0,0.0E+0]
; AVX10_2-NEXT: retq
;
; X86-LABEL: test_fmaximum_snan:
; X86: # %bb.0:
; X86-NEXT: flds {{\.?LCPI[0-9]+_[0-9]+}}
; X86-NEXT: retl
%1 = tail call float @llvm.maximum.f32(float 0x7ff4000000000000, float %x)
ret float %1
}

define float @test_fminimum_snan(float %x) {
; SSE2-LABEL: test_fminimum_snan:
; SSE2: # %bb.0:
; SSE2-NEXT: movss {{.*#+}} xmm0 = [NaN,0.0E+0,0.0E+0,0.0E+0]
; SSE2-NEXT: retq
;
; AVX-LABEL: test_fminimum_snan:
; AVX: # %bb.0:
; AVX-NEXT: vmovss {{.*#+}} xmm0 = [NaN,0.0E+0,0.0E+0,0.0E+0]
; AVX-NEXT: retq
;
; AVX10_2-LABEL: test_fminimum_snan:
; AVX10_2: # %bb.0:
; AVX10_2-NEXT: vmovss {{.*#+}} xmm0 = [NaN,0.0E+0,0.0E+0,0.0E+0]
; AVX10_2-NEXT: retq
;
; X86-LABEL: test_fminimum_snan:
; X86: # %bb.0:
; X86-NEXT: flds {{\.?LCPI[0-9]+_[0-9]+}}
; X86-NEXT: retl
%1 = tail call float @llvm.minimum.f32(float 0x7ff4000000000000, float %x)
ret float %1
}
99 changes: 99 additions & 0 deletions llvm/test/CodeGen/X86/fminimumnum-fmaximumnum.ll
Original file line number Diff line number Diff line change
Expand Up @@ -2479,3 +2479,102 @@ define <4 x bfloat> @test_fmaximumnum_v4bf16(<4 x bfloat> %x, <4 x bfloat> %y) n
%r = call <4 x bfloat> @llvm.maximumnum.v4bf16(<4 x bfloat> %x, <4 x bfloat> %y)
ret <4 x bfloat> %r
}

; nnan minimumnum(Y, +inf) -> Y
define float @test_fminimumnum_inf_nnan(float %x, float %y) nounwind {
; SSE2-LABEL: test_fminimumnum_inf_nnan:
; SSE2: # %bb.0:
; SSE2-NEXT: movaps %xmm1, %xmm0
; SSE2-NEXT: retq
;
; AVX-LABEL: test_fminimumnum_inf_nnan:
; AVX: # %bb.0:
; AVX-NEXT: vmovaps %xmm1, %xmm0
; AVX-NEXT: retq
;
; AVX10_2-LABEL: test_fminimumnum_inf_nnan:
; AVX10_2: # %bb.0:
; AVX10_2-NEXT: vmovaps %xmm1, %xmm0
; AVX10_2-NEXT: retq
;
; X86-LABEL: test_fminimumnum_inf_nnan:
; X86: # %bb.0:
; X86-NEXT: flds {{[0-9]+}}(%esp)
; X86-NEXT: retl
%1 = call nnan float @llvm.minimumnum.f32(float %y, float 0x7ff0000000000000)
ret float %1
}

; nnan maximumnum(Y, -inf) -> Y
define float @test_fmaximumnum_neg_inf_nnan(float %x, float %y) nounwind {
; SSE2-LABEL: test_fmaximumnum_neg_inf_nnan:
; SSE2: # %bb.0:
; SSE2-NEXT: movaps %xmm1, %xmm0
; SSE2-NEXT: retq
;
; AVX-LABEL: test_fmaximumnum_neg_inf_nnan:
; AVX: # %bb.0:
; AVX-NEXT: vmovaps %xmm1, %xmm0
; AVX-NEXT: retq
;
; AVX10_2-LABEL: test_fmaximumnum_neg_inf_nnan:
; AVX10_2: # %bb.0:
; AVX10_2-NEXT: vmovaps %xmm1, %xmm0
; AVX10_2-NEXT: retq
;
; X86-LABEL: test_fmaximumnum_neg_inf_nnan:
; X86: # %bb.0:
; X86-NEXT: flds {{[0-9]+}}(%esp)
; X86-NEXT: retl
%1 = call nnan float @llvm.maximumnum.f32(float %y, float 0xfff0000000000000)
ret float %1
}

; Test we propagate the non-NaN arg, even if one arg is SNaN
define float @test_fmaximumnum_snan(float %x, float %y) {
; SSE2-LABEL: test_fmaximumnum_snan:
; SSE2: # %bb.0:
; SSE2-NEXT: movaps %xmm1, %xmm0
; SSE2-NEXT: retq
;
; AVX-LABEL: test_fmaximumnum_snan:
; AVX: # %bb.0:
; AVX-NEXT: vmovaps %xmm1, %xmm0
; AVX-NEXT: retq
;
; AVX10_2-LABEL: test_fmaximumnum_snan:
; AVX10_2: # %bb.0:
; AVX10_2-NEXT: vmovaps %xmm1, %xmm0
; AVX10_2-NEXT: retq
;
; X86-LABEL: test_fmaximumnum_snan:
; X86: # %bb.0:
; X86-NEXT: flds {{[0-9]+}}(%esp)
; X86-NEXT: retl
%1 = tail call float @llvm.maximumnum.f32(float 0x7ff4000000000000, float %y)
ret float %1
}

define float @test_fminimumnum_snan(float %x, float %y) {
; SSE2-LABEL: test_fminimumnum_snan:
; SSE2: # %bb.0:
; SSE2-NEXT: movaps %xmm1, %xmm0
; SSE2-NEXT: retq
;
; AVX-LABEL: test_fminimumnum_snan:
; AVX: # %bb.0:
; AVX-NEXT: vmovaps %xmm1, %xmm0
; AVX-NEXT: retq
;
; AVX10_2-LABEL: test_fminimumnum_snan:
; AVX10_2: # %bb.0:
; AVX10_2-NEXT: vmovaps %xmm1, %xmm0
; AVX10_2-NEXT: retq
;
; X86-LABEL: test_fminimumnum_snan:
; X86: # %bb.0:
; X86-NEXT: flds {{[0-9]+}}(%esp)
; X86-NEXT: retl
%1 = tail call float @llvm.minimumnum.f32(float 0x7ff4000000000000, float %y)
ret float %1
}
46 changes: 41 additions & 5 deletions llvm/test/CodeGen/X86/fminnum.ll
Original file line number Diff line number Diff line change
Expand Up @@ -645,11 +645,47 @@ define float @test_minnum_const_op2(float %x) {
ret float %r
}

define float @test_minnum_const_nan(float %x) {
; CHECK-LABEL: test_minnum_const_nan:
; CHECK: # %bb.0:
; CHECK-NEXT: retq
%r = call float @llvm.minnum.f32(float %x, float 0x7fff000000000000)
define float @test_minnum_const_nan(float %x, float %y) {
; SSE-LABEL: test_minnum_const_nan:
; SSE: # %bb.0:
; SSE-NEXT: movaps %xmm1, %xmm0
; SSE-NEXT: retq
;
; AVX-LABEL: test_minnum_const_nan:
; AVX: # %bb.0:
; AVX-NEXT: vmovaps %xmm1, %xmm0
; AVX-NEXT: retq
%r = call float @llvm.minnum.f32(float %y, float 0x7fff000000000000)
ret float %r
}

; nnan minnum(Y, +inf) -> Y
define float @test_minnum_inf_nnan(float %x, float %y) nounwind {
; SSE-LABEL: test_minnum_inf_nnan:
; SSE: # %bb.0:
; SSE-NEXT: movaps %xmm1, %xmm0
; SSE-NEXT: retq
;
; AVX-LABEL: test_minnum_inf_nnan:
; AVX: # %bb.0:
; AVX-NEXT: vmovaps %xmm1, %xmm0
; AVX-NEXT: retq
%r = call nnan float @llvm.minnum.f32(float %y, float 0x7ff0000000000000)
ret float %r
}

; Test SNaN quieting
define float @test_minnum_snan(float %x) {
; SSE-LABEL: test_minnum_snan:
; SSE: # %bb.0:
; SSE-NEXT: movss {{.*#+}} xmm0 = [NaN,0.0E+0,0.0E+0,0.0E+0]
; SSE-NEXT: retq
;
; AVX-LABEL: test_minnum_snan:
; AVX: # %bb.0:
; AVX-NEXT: vmovss {{.*#+}} xmm0 = [NaN,0.0E+0,0.0E+0,0.0E+0]
; AVX-NEXT: retq
%r = call float @llvm.minnum.f32(float 0x7ff4000000000000, float %x)
ret float %r
}

Expand Down