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
4 changes: 4 additions & 0 deletions llvm/lib/Analysis/ConstantFolding.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3348,8 +3348,12 @@ static Constant *ConstantFoldIntrinsicCall2(Intrinsic::ID IntrinsicID, Type *Ty,
case Intrinsic::copysign:
return ConstantFP::get(Ty->getContext(), APFloat::copySign(Op1V, Op2V));
case Intrinsic::minnum:
if (Op1V.isSignaling() || Op2V.isSignaling())
return nullptr;
return ConstantFP::get(Ty->getContext(), minnum(Op1V, Op2V));
case Intrinsic::maxnum:
if (Op1V.isSignaling() || Op2V.isSignaling())
return nullptr;
return ConstantFP::get(Ty->getContext(), maxnum(Op1V, Op2V));
case Intrinsic::minimum:
return ConstantFP::get(Ty->getContext(), minimum(Op1V, Op2V));
Expand Down
25 changes: 11 additions & 14 deletions llvm/lib/Analysis/InstructionSimplify.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6620,7 +6620,8 @@ static MinMaxOptResult OptimizeConstMinMax(const Constant *RHSConst,
assert(OutNewConstVal != nullptr);

bool PropagateNaN = IID == Intrinsic::minimum || IID == Intrinsic::maximum;
bool PropagateSNaN = IID == Intrinsic::minnum || IID == Intrinsic::maxnum;
bool ReturnsOtherForAllNaNs =
IID == Intrinsic::minimumnum || IID == Intrinsic::maximumnum;
bool IsMin = IID == Intrinsic::minimum || IID == Intrinsic::minnum ||
IID == Intrinsic::minimumnum;

Expand All @@ -6637,29 +6638,27 @@ static MinMaxOptResult OptimizeConstMinMax(const Constant *RHSConst,

// 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 (CAPF.isNaN()) {
if (PropagateNaN || (PropagateSNaN && CAPF.isSignaling())) {
if (PropagateNaN) {
*OutNewConstVal = ConstantFP::get(CFP->getType(), CAPF.makeQuiet());
return MinMaxOptResult::UseNewConstVal;
} else if (ReturnsOtherForAllNaNs || !CAPF.isSignaling()) {
return MinMaxOptResult::UseOtherVal;
}
return MinMaxOptResult::UseOtherVal;
return MinMaxOptResult::CannotOptimize;
}

if (CAPF.isInfinity() || (Call && Call->hasNoInfs() && CAPF.isLargest())) {
// 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 (CAPF.isNegative() == IsMin &&
(!PropagateNaN || (Call && Call->hasNoNaNs()))) {
(ReturnsOtherForAllNaNs || (Call && Call->hasNoNaNs()))) {
*OutNewConstVal = const_cast<Constant *>(RHSConst);
return MinMaxOptResult::UseNewConstVal;
}
Expand Down Expand Up @@ -7004,12 +7003,10 @@ Value *llvm::simplifyBinaryIntrinsic(Intrinsic::ID IID, Type *ReturnType,
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 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.
// In some cases here, we deviate from exact IEEE-754 semantics to enable
// optimizations (as allowed by the LLVM IR spec) by returning one of the
// arguments unmodified instead of inserting an llvm.canonicalize to
// transform input sNaNs into qNaNs,

// If the arguments are the same, this is a no-op (ignoring NaN quieting)
if (Op0 == Op1)
Expand Down
4 changes: 4 additions & 0 deletions llvm/lib/CodeGen/GlobalISel/Utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -768,8 +768,12 @@ llvm::ConstantFoldFPBinOp(unsigned Opcode, const Register Op1,
C1.copySign(C2);
return C1;
case TargetOpcode::G_FMINNUM:
if (C1.isSignaling() || C2.isSignaling())
return std::nullopt;
return minnum(C1, C2);
case TargetOpcode::G_FMAXNUM:
if (C1.isSignaling() || C2.isSignaling())
return std::nullopt;
return maxnum(C1, C2);
case TargetOpcode::G_FMINIMUM:
return minimum(C1, C2);
Expand Down
15 changes: 7 additions & 8 deletions llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19505,7 +19505,8 @@ SDValue DAGCombiner::visitFMinMax(SDNode *N) {
const SDNodeFlags Flags = N->getFlags();
unsigned Opc = N->getOpcode();
bool PropAllNaNsToQNaNs = Opc == ISD::FMINIMUM || Opc == ISD::FMAXIMUM;
bool PropOnlySNaNsToQNaNs = Opc == ISD::FMINNUM || Opc == ISD::FMAXNUM;
bool ReturnsOtherForAllNaNs =
Opc == ISD::FMINIMUMNUM || Opc == ISD::FMAXIMUMNUM;
bool IsMin =
Opc == ISD::FMINNUM || Opc == ISD::FMINIMUM || Opc == ISD::FMINIMUMNUM;
SelectionDAG::FlagInserter FlagsInserter(DAG, N);
Expand All @@ -19524,32 +19525,30 @@ SDValue DAGCombiner::visitFMinMax(SDNode *N) {

// 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 (PropAllNaNsToQNaNs) {
if (AF.isSignaling())
return DAG.getConstantFP(AF.makeQuiet(), SDLoc(N), VT);
return N->getOperand(1);
} else if (ReturnsOtherForAllNaNs || !AF.isSignaling()) {
return N->getOperand(0);
}
return N->getOperand(0);
return SDValue();
}

// 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 (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 (IsMin == AF.isNegative() &&
(!PropAllNaNsToQNaNs || Flags.hasNoNaNs()))
(ReturnsOtherForAllNaNs || Flags.hasNoNaNs()))
return N->getOperand(1);

// minnum(X, +inf) -> X if nnan
Expand Down
4 changes: 4 additions & 0 deletions llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7382,8 +7382,12 @@ SDValue SelectionDAG::foldConstantFPMath(unsigned Opcode, const SDLoc &DL,
C1.copySign(C2);
return getConstantFP(C1, DL, VT);
case ISD::FMINNUM:
if (C1.isSignaling() || C2.isSignaling())
return SDValue();
return getConstantFP(minnum(C1, C2), DL, VT);
case ISD::FMAXNUM:
if (C1.isSignaling() || C2.isSignaling())
return SDValue();
return getConstantFP(maxnum(C1, C2), DL, VT);
case ISD::FMINIMUM:
return getConstantFP(minimum(C1, C2), DL, VT);
Expand Down
6 changes: 4 additions & 2 deletions llvm/test/CodeGen/AMDGPU/fcanonicalize-elimination.ll
Original file line number Diff line number Diff line change
Expand Up @@ -497,10 +497,12 @@ define amdgpu_kernel void @test_fold_canonicalize_minnum_value_f32(ptr addrspace
ret void
}

; FIXME: Should there be more checks here? minnum with sNaN operand is simplified to qNaN.
; FIXME: Should there be more checks here? minnum with sNaN operand might get simplified away.

; GCN-LABEL: test_fold_canonicalize_sNaN_value_f32:
; GCN: v_mov_b32_e32 v{{.+}}, 0x7fc00000
; 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]]
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
Expand Down
39 changes: 32 additions & 7 deletions llvm/test/CodeGen/ARM/fminmax-folds.ll
Original file line number Diff line number Diff line change
Expand Up @@ -65,9 +65,15 @@ define float @test_minnum_const_inf(float %x) {
define float @test_maxnum_const_inf(float %x) {
; CHECK-LABEL: test_maxnum_const_inf:
; CHECK: @ %bb.0:
; CHECK-NEXT: movw r0, #0
; CHECK-NEXT: movt r0, #32640
; CHECK-NEXT: vldr s0, .LCPI5_0
; CHECK-NEXT: vmov s2, r0
; CHECK-NEXT: vmaxnm.f32 s0, s2, s0
; CHECK-NEXT: vmov r0, s0
; CHECK-NEXT: bx lr
; CHECK-NEXT: .p2align 2
; CHECK-NEXT: @ %bb.1:
; CHECK-NEXT: .LCPI5_0:
; CHECK-NEXT: .long 0x7f800000 @ float +Inf
%r = call float @llvm.maxnum.f32(float %x, float 0x7ff0000000000000)
ret float %r
}
Expand Down Expand Up @@ -99,9 +105,15 @@ define float @test_minimum_const_inf(float %x) {
define float @test_minnum_const_neg_inf(float %x) {
; CHECK-LABEL: test_minnum_const_neg_inf:
; CHECK: @ %bb.0:
; CHECK-NEXT: movw r0, #0
; CHECK-NEXT: movt r0, #65408
; CHECK-NEXT: vldr s0, .LCPI8_0
; CHECK-NEXT: vmov s2, r0
; CHECK-NEXT: vminnm.f32 s0, s2, s0
; CHECK-NEXT: vmov r0, s0
; CHECK-NEXT: bx lr
; CHECK-NEXT: .p2align 2
; CHECK-NEXT: @ %bb.1:
; CHECK-NEXT: .LCPI8_0:
; CHECK-NEXT: .long 0xff800000 @ float -Inf
%r = call float @llvm.minnum.f32(float %x, float 0xfff0000000000000)
ret float %r
}
Expand Down Expand Up @@ -447,9 +459,15 @@ define float @test_minnum_const_max_ninf(float %x) {
define float @test_maxnum_const_max_ninf(float %x) {
; CHECK-LABEL: test_maxnum_const_max_ninf:
; CHECK: @ %bb.0:
; CHECK-NEXT: movw r0, #65535
; CHECK-NEXT: movt r0, #32639
; CHECK-NEXT: vldr s0, .LCPI37_0
; CHECK-NEXT: vmov s2, r0
; CHECK-NEXT: vmaxnm.f32 s0, s2, s0
; CHECK-NEXT: vmov r0, s0
; CHECK-NEXT: bx lr
; CHECK-NEXT: .p2align 2
; CHECK-NEXT: @ %bb.1:
; CHECK-NEXT: .LCPI37_0:
; CHECK-NEXT: .long 0x7f7fffff @ float 3.40282347E+38
%r = call ninf float @llvm.maxnum.f32(float %x, float 0x47efffffe0000000)
ret float %r
}
Expand Down Expand Up @@ -481,8 +499,15 @@ define float @test_minimum_const_max_ninf(float %x) {
define float @test_minnum_const_neg_max_ninf(float %x) {
; CHECK-LABEL: test_minnum_const_neg_max_ninf:
; CHECK: @ %bb.0:
; CHECK-NEXT: mvn r0, #8388608
; CHECK-NEXT: vldr s0, .LCPI40_0
; CHECK-NEXT: vmov s2, r0
; CHECK-NEXT: vminnm.f32 s0, s2, s0
; CHECK-NEXT: vmov r0, s0
; CHECK-NEXT: bx lr
; CHECK-NEXT: .p2align 2
; CHECK-NEXT: @ %bb.1:
; CHECK-NEXT: .LCPI40_0:
; CHECK-NEXT: .long 0xff7fffff @ float -3.40282347E+38
%r = call ninf float @llvm.minnum.f32(float %x, float 0xc7efffffe0000000)
ret float %r
}
Expand Down
45 changes: 37 additions & 8 deletions llvm/test/CodeGen/X86/fmaxnum.ll
Original file line number Diff line number Diff line change
Expand Up @@ -676,15 +676,44 @@ define float @test_maxnum_neg_inf_nnan(float %x, float %y) nounwind {

; 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
; SSE2-LABEL: test_maxnum_snan:
; SSE2: # %bb.0:
; SSE2-NEXT: movss {{.*#+}} xmm2 = [NaN,0.0E+0,0.0E+0,0.0E+0]
; SSE2-NEXT: movaps %xmm0, %xmm1
; SSE2-NEXT: cmpunordss %xmm0, %xmm1
; SSE2-NEXT: movaps %xmm1, %xmm3
; SSE2-NEXT: andps %xmm2, %xmm3
; SSE2-NEXT: maxss %xmm0, %xmm2
; SSE2-NEXT: andnps %xmm2, %xmm1
; SSE2-NEXT: orps %xmm3, %xmm1
; SSE2-NEXT: movaps %xmm1, %xmm0
; SSE2-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
; SSE4-LABEL: test_maxnum_snan:
; SSE4: # %bb.0:
; SSE4-NEXT: movss {{.*#+}} xmm1 = [NaN,0.0E+0,0.0E+0,0.0E+0]
; SSE4-NEXT: maxss %xmm0, %xmm1
; SSE4-NEXT: cmpunordss %xmm0, %xmm0
; SSE4-NEXT: blendvps %xmm0, {{\.?LCPI[0-9]+_[0-9]+}}(%rip), %xmm1
; SSE4-NEXT: movaps %xmm1, %xmm0
; SSE4-NEXT: retq
;
; AVX1-LABEL: test_maxnum_snan:
; AVX1: # %bb.0:
; AVX1-NEXT: vmovss {{.*#+}} xmm1 = [NaN,0.0E+0,0.0E+0,0.0E+0]
; AVX1-NEXT: vmaxss %xmm0, %xmm1, %xmm1
; AVX1-NEXT: vcmpunordss %xmm0, %xmm0, %xmm0
; AVX1-NEXT: vblendvps %xmm0, {{\.?LCPI[0-9]+_[0-9]+}}(%rip), %xmm1, %xmm0
; AVX1-NEXT: retq
;
; AVX512-LABEL: test_maxnum_snan:
; AVX512: # %bb.0:
; AVX512-NEXT: vmovss {{.*#+}} xmm2 = [NaN,0.0E+0,0.0E+0,0.0E+0]
; AVX512-NEXT: vmaxss %xmm0, %xmm2, %xmm1
; AVX512-NEXT: vcmpunordss %xmm0, %xmm0, %k1
; AVX512-NEXT: vmovss %xmm2, %xmm1, %xmm1 {%k1}
; AVX512-NEXT: vmovaps %xmm1, %xmm0
; AVX512-NEXT: retq
%r = call float @llvm.maxnum.f32(float 0x7ff4000000000000, float %x)
ret float %r
}
Expand Down
45 changes: 37 additions & 8 deletions llvm/test/CodeGen/X86/fminnum.ll
Original file line number Diff line number Diff line change
Expand Up @@ -676,15 +676,44 @@ define float @test_minnum_inf_nnan(float %x, float %y) nounwind {

; 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
; SSE2-LABEL: test_minnum_snan:
; SSE2: # %bb.0:
; SSE2-NEXT: movss {{.*#+}} xmm2 = [NaN,0.0E+0,0.0E+0,0.0E+0]
; SSE2-NEXT: movaps %xmm0, %xmm1
; SSE2-NEXT: cmpunordss %xmm0, %xmm1
; SSE2-NEXT: movaps %xmm1, %xmm3
; SSE2-NEXT: andps %xmm2, %xmm3
; SSE2-NEXT: minss %xmm0, %xmm2
; SSE2-NEXT: andnps %xmm2, %xmm1
; SSE2-NEXT: orps %xmm3, %xmm1
; SSE2-NEXT: movaps %xmm1, %xmm0
; SSE2-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
; SSE4-LABEL: test_minnum_snan:
; SSE4: # %bb.0:
; SSE4-NEXT: movss {{.*#+}} xmm1 = [NaN,0.0E+0,0.0E+0,0.0E+0]
; SSE4-NEXT: minss %xmm0, %xmm1
; SSE4-NEXT: cmpunordss %xmm0, %xmm0
; SSE4-NEXT: blendvps %xmm0, {{\.?LCPI[0-9]+_[0-9]+}}(%rip), %xmm1
; SSE4-NEXT: movaps %xmm1, %xmm0
; SSE4-NEXT: retq
;
; AVX1-LABEL: test_minnum_snan:
; AVX1: # %bb.0:
; AVX1-NEXT: vmovss {{.*#+}} xmm1 = [NaN,0.0E+0,0.0E+0,0.0E+0]
; AVX1-NEXT: vminss %xmm0, %xmm1, %xmm1
; AVX1-NEXT: vcmpunordss %xmm0, %xmm0, %xmm0
; AVX1-NEXT: vblendvps %xmm0, {{\.?LCPI[0-9]+_[0-9]+}}(%rip), %xmm1, %xmm0
; AVX1-NEXT: retq
;
; AVX512-LABEL: test_minnum_snan:
; AVX512: # %bb.0:
; AVX512-NEXT: vmovss {{.*#+}} xmm2 = [NaN,0.0E+0,0.0E+0,0.0E+0]
; AVX512-NEXT: vminss %xmm0, %xmm2, %xmm1
; AVX512-NEXT: vcmpunordss %xmm0, %xmm0, %k1
; AVX512-NEXT: vmovss %xmm2, %xmm1, %xmm1 {%k1}
; AVX512-NEXT: vmovaps %xmm1, %xmm0
Comment on lines +713 to +715

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

probably something for a different PR,
but this really looks like a use case for VFIXUPIMMP[SD] with [QS]NaN to src1

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A MOVSS is enough if NaN is known. But we don't need bother doing this in each backend. Just waiting for the code in DAGCombiner.cpp‎ brought back :)

; AVX512-NEXT: retq
%r = call float @llvm.minnum.f32(float 0x7ff4000000000000, float %x)
ret float %r
}
Expand Down
6 changes: 4 additions & 2 deletions llvm/test/Transforms/InstCombine/simplify-demanded-fpclass.ll
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ declare float @llvm.trunc.f32(float)
declare float @llvm.arithmetic.fence.f32(float)
declare float @llvm.minnum.f32(float, float)
declare float @llvm.maxnum.f32(float, float)
declare float @llvm.minimumnum.f32(float, float)
declare float @llvm.maximumnum.f32(float, float)


define float @ninf_user_select_inf(i1 %cond, float %x, float %y) {
Expand Down Expand Up @@ -1314,7 +1316,7 @@ define nofpclass(pinf) float @ret_nofpclass_pinf__minnum_ninf(i1 %cond, float %x
; CHECK-SAME: (i1 [[COND:%.*]], float [[X:%.*]]) {
; CHECK-NEXT: ret float 0xFFF0000000000000
;
%min = call float @llvm.minnum.f32(float %x, float 0xFFF0000000000000)
%min = call float @llvm.minimumnum.f32(float %x, float 0xFFF0000000000000)
ret float %min
}

Expand All @@ -1335,6 +1337,6 @@ define nofpclass(ninf) float @ret_nofpclass_ninf__maxnum_pinf(i1 %cond, float %x
; CHECK-SAME: (i1 [[COND:%.*]], float [[X:%.*]]) {
; CHECK-NEXT: ret float 0x7FF0000000000000
;
%max = call float @llvm.maxnum.f32(float %x, float 0x7FF0000000000000)
%max = call float @llvm.maximumnum.f32(float %x, float 0x7FF0000000000000)
ret float %max
}
Loading