Index: docs/LangRef.rst =================================================================== --- docs/LangRef.rst +++ docs/LangRef.rst @@ -11560,6 +11560,84 @@ correctly return the non-NaN input (e.g. by using the equivalent of ``llvm.canonicalize``). +'``llvm.minnan.*``' Intrinsic +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Syntax: +""""""" + +This is an overloaded intrinsic. You can use ``llvm.minnan`` on any +floating-point or vector of floating-point type. Not all targets support +all types however. + +:: + + declare float @llvm.minnan.f32(float %Val0, float %Val1) + declare double @llvm.minnan.f64(double %Val0, double %Val1) + declare x86_fp80 @llvm.minnan.f80(x86_fp80 %Val0, x86_fp80 %Val1) + declare fp128 @llvm.minnan.f128(fp128 %Val0, fp128 %Val1) + declare ppc_fp128 @llvm.minnan.ppcf128(ppc_fp128 %Val0, ppc_fp128 %Val1) + +Overview: +""""""""" + +The '``llvm.minnan.*``' intrinsics return the minimum of the two +arguments, propagating NaNs. + + +Arguments: +"""""""""" + +The arguments and return value are floating-point numbers of the same +type. + +Semantics: +"""""""""" +If either operand is a NaN, returns NaN. If the operands compare +equal, returns a value that compares equal to both operands. This +means that llvm.minnan(+/-0.0, +/-0.0) could return either -0.0 or +0.0. Note that this is different from IEEE 754-2018 semantics, which +require that -0 compare less than +0 for this operation. + +'``llvm.maxnan.*``' Intrinsic +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Syntax: +""""""" + +This is an overloaded intrinsic. You can use ``llvm.maxnan`` on any +floating-point or vector of floating-point type. Not all targets support +all types however. + +:: + + declare float @llvm.maxnan.f32(float %Val0, float %Val1l) + declare double @llvm.maxnan.f64(double %Val0, double %Val1) + declare x86_fp80 @llvm.maxnan.f80(x86_fp80 %Val0, x86_fp80 %Val1) + declare fp128 @llvm.maxnan.f128(fp128 %Val0, fp128 %Val1) + declare ppc_fp128 @llvm.maxnan.ppcf128(ppc_fp128 %Val0, ppc_fp128 %Val1) + +Overview: +""""""""" + +The '``llvm.maxnan.*``' intrinsics return the maximum of the two +arguments, propagating NaNs. + + +Arguments: +"""""""""" + +The arguments and return value are floating-point numbers of the same +type. + +Semantics: +"""""""""" +If either operand is a NaN, returns NaN. If the operands compare +equal, returns a value that compares equal to both operands. This +means that llvm.maxnan(+/-0.0, +/-0.0) could return either -0.0 or +0.0.Note that this is different from IEEE 754-2018 semantics, which +require that -0 compare less than +0 for this operation. + '``llvm.copysign.*``' Intrinsic ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Index: include/llvm/ADT/APFloat.h =================================================================== --- include/llvm/ADT/APFloat.h +++ include/llvm/ADT/APFloat.h @@ -1243,6 +1243,30 @@ return (A.compare(B) == APFloat::cmpLessThan) ? B : A; } +/// Returns the smaller of the 2 arguments if both are not Nan. If either +/// argument is a NaN, return the NaN. Implements IEEE 754-2018 `minimum` +/// semantics, except that -0 does not necessarily compare less than +0. +LLVM_READONLY +inline APFloat minnan(const APFloat &A, const APFloat &B) { + if (A.isNaN()) + return A; + if (B.isNaN()) + return B; + return (B.compare(A) == APFloat::cmpLessThan) ? B : A; +} + +/// Returns the larger of the 2 arguments if both are not Nan. If either +/// argument is a NaN, return the NaN. Implements IEEE 754-2018 `maximum` +/// semantics, except that -0 does not necessarily compare less than +0. +LLVM_READONLY +inline APFloat maxnan(const APFloat &A, const APFloat &B) { + if (A.isNaN()) + return A; + if (B.isNaN()) + return B; + return (A.compare(B) == APFloat::cmpLessThan) ? B : A; +} + } // namespace llvm #undef APFLOAT_DISPATCH_ON_SEMANTICS Index: include/llvm/IR/IRBuilder.h =================================================================== --- include/llvm/IR/IRBuilder.h +++ include/llvm/IR/IRBuilder.h @@ -703,6 +703,16 @@ return CreateBinaryIntrinsic(Intrinsic::maxnum, LHS, RHS, Name); } + /// Create call to the minnan intrinsic. + CallInst *CreateMinNan(Value *LHS, Value *RHS, const Twine &Name = "") { + return CreateBinaryIntrinsic(Intrinsic::minnan, LHS, RHS, Name); + } + + /// Create call to the maxnan intrinsic. + CallInst *CreateMaxNan(Value *LHS, Value *RHS, const Twine &Name = "") { + return CreateBinaryIntrinsic(Intrinsic::maxnan, LHS, RHS, Name); + } + private: /// Create a call to a masked intrinsic with given Id. CallInst *CreateMaskedIntrinsic(Intrinsic::ID Id, ArrayRef Ops, Index: include/llvm/IR/Intrinsics.td =================================================================== --- include/llvm/IR/Intrinsics.td +++ include/llvm/IR/Intrinsics.td @@ -453,6 +453,14 @@ [LLVMMatchType<0>, LLVMMatchType<0>], [IntrNoMem, IntrSpeculatable, Commutative] >; +def int_minnan : Intrinsic<[llvm_anyfloat_ty], + [LLVMMatchType<0>, LLVMMatchType<0>], + [IntrNoMem, IntrSpeculatable, Commutative] +>; +def int_maxnan : Intrinsic<[llvm_anyfloat_ty], + [LLVMMatchType<0>, LLVMMatchType<0>], + [IntrNoMem, IntrSpeculatable, Commutative] +>; // NOTE: these are internal interfaces. def int_setjmp : Intrinsic<[llvm_i32_ty], [llvm_ptr_ty]>; Index: lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp =================================================================== --- lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp +++ lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp @@ -5584,6 +5584,18 @@ getValue(I.getArgOperand(1)))); return nullptr; } + case Intrinsic::minnan: + setValue(&I, DAG.getNode(ISD::FMINNAN, sdl, + getValue(I.getArgOperand(0)).getValueType(), + getValue(I.getArgOperand(0)), + getValue(I.getArgOperand(1)))); + return nullptr; + case Intrinsic::maxnan: + setValue(&I, DAG.getNode(ISD::FMAXNAN, sdl, + getValue(I.getArgOperand(0)).getValueType(), + getValue(I.getArgOperand(0)), + getValue(I.getArgOperand(1)))); + return nullptr; case Intrinsic::copysign: setValue(&I, DAG.getNode(ISD::FCOPYSIGN, sdl, getValue(I.getArgOperand(0)).getValueType(), Index: unittests/IR/IRBuilderTest.cpp =================================================================== --- unittests/IR/IRBuilderTest.cpp +++ unittests/IR/IRBuilderTest.cpp @@ -64,6 +64,14 @@ II = cast(Call); EXPECT_EQ(II->getIntrinsicID(), Intrinsic::maxnum); + Call = Builder.CreateMinNan(V, V); + II = cast(Call); + EXPECT_EQ(II->getIntrinsicID(), Intrinsic::minnan); + + Call = Builder.CreateMaxNan(V, V); + II = cast(Call); + EXPECT_EQ(II->getIntrinsicID(), Intrinsic::maxnan); + Call = Builder.CreateIntrinsic(Intrinsic::readcyclecounter); II = cast(Call); EXPECT_EQ(II->getIntrinsicID(), Intrinsic::readcyclecounter);