Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
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
}
12 changes: 8 additions & 4 deletions llvm/test/Transforms/InstSimplify/ConstProp/min-max.ll
Original file line number Diff line number Diff line change
Expand Up @@ -97,15 +97,17 @@ define float @minnum_float_qnan_p0() {

define float @minnum_float_p0_snan() {
; CHECK-LABEL: @minnum_float_p0_snan(
; CHECK-NEXT: ret float 0x7FFC000000000000
; CHECK-NEXT: [[MIN:%.*]] = call float @llvm.minnum.f32(float 0.000000e+00, float 0x7FF4000000000000)
; CHECK-NEXT: ret float [[MIN]]
;
%min = call float @llvm.minnum.f32(float 0.0, float 0x7FF4000000000000)
ret float %min
}

define float @minnum_float_snan_p0() {
; CHECK-LABEL: @minnum_float_snan_p0(
; CHECK-NEXT: ret float 0x7FFC000000000000
; CHECK-NEXT: [[MIN:%.*]] = call float @llvm.minnum.f32(float 0x7FF4000000000000, float 0.000000e+00)
; CHECK-NEXT: ret float [[MIN]]
;
%min = call float @llvm.minnum.f32(float 0x7FF4000000000000, float 0.0)
ret float %min
Expand Down Expand Up @@ -205,15 +207,17 @@ define float @maxnum_float_qnan_p0() {

define float @maxnum_float_p0_snan() {
; CHECK-LABEL: @maxnum_float_p0_snan(
; CHECK-NEXT: ret float 0x7FFC000000000000
; CHECK-NEXT: [[MAX:%.*]] = call float @llvm.maxnum.f32(float 0.000000e+00, float 0x7FF4000000000000)
; CHECK-NEXT: ret float [[MAX]]
;
%max = call float @llvm.maxnum.f32(float 0.0, float 0x7FF4000000000000)
ret float %max
}

define float @maxnum_float_snan_p0() {
; CHECK-LABEL: @maxnum_float_snan_p0(
; CHECK-NEXT: ret float 0x7FFC000000000000
; CHECK-NEXT: [[MAX:%.*]] = call float @llvm.maxnum.f32(float 0x7FF4000000000000, float 0.000000e+00)
; CHECK-NEXT: ret float [[MAX]]
;
%max = call float @llvm.maxnum.f32(float 0x7FF4000000000000, float 0.0)
ret float %max
Expand Down
Loading
Loading