llvm.org GIT mirror llvm / 6e3463c
[Intrinsic] Add llvm.minimum and llvm.maximum instrinsic functions Summary: These new intrinsics have the semantics of the `minimum` and `maximum` operations specified by the latest draft of IEEE 754-2018. Unlike llvm.minnum and llvm.maxnum, these new intrinsics propagate NaNs and always treat -0.0 as less than 0.0. `minimum` and `maximum` lower directly to the existing `fminnan` and `fmaxnan` ISel DAG nodes. It is safe to reuse these DAG nodes because before this patch were only emitted in situations where there were known to be no NaN arguments or where NaN propagation was correct and there were known to be no zero arguments. I know of only four backends that lower fminnan and fmaxnan: WebAssembly, ARM, AArch64, and SystemZ, and each of these lowers fminnan and fmaxnan to instructions that are compatible with the IEEE 754-2018 semantics. Reviewers: aheejin, dschuff, sunfish, javed.absar Subscribers: kristof.beyls, dexonsmith, kristina, llvm-commits Differential Revision: https://reviews.llvm.org/D52764 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@344437 91177308-0d34-0410-b5e6-96231b3b80d8 Thomas Lively 2 years ago
8 changed file(s) with 173 addition(s) and 2 deletion(s). Raw diff Collapse all Expand all
1155911559 correctly return the non-NaN input (e.g. by using the equivalent of
1156011560 ``llvm.canonicalize``).
1156111561
11562 '``llvm.minimum.*``' Intrinsic
11563 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
11564
11565 Syntax:
11566 """""""
11567
11568 This is an overloaded intrinsic. You can use ``llvm.minimum`` on any
11569 floating-point or vector of floating-point type. Not all targets support
11570 all types however.
11571
11572 ::
11573
11574 declare float @llvm.minimum.f32(float %Val0, float %Val1)
11575 declare double @llvm.minimum.f64(double %Val0, double %Val1)
11576 declare x86_fp80 @llvm.minimum.f80(x86_fp80 %Val0, x86_fp80 %Val1)
11577 declare fp128 @llvm.minimum.f128(fp128 %Val0, fp128 %Val1)
11578 declare ppc_fp128 @llvm.minimum.ppcf128(ppc_fp128 %Val0, ppc_fp128 %Val1)
11579
11580 Overview:
11581 """""""""
11582
11583 The '``llvm.minimum.*``' intrinsics return the minimum of the two
11584 arguments, propagating NaNs and treating -0.0 as less than +0.0.
11585
11586
11587 Arguments:
11588 """"""""""
11589
11590 The arguments and return value are floating-point numbers of the same
11591 type.
11592
11593 Semantics:
11594 """"""""""
11595 If either operand is a NaN, returns NaN. Otherwise returns the lesser
11596 of the two arguments. -0.0 is considered to be less than +0.0 for this
11597 intrinsic. Note that these are the semantics specified in the draft of
11598 IEEE 754-2018.
11599
11600 '``llvm.maximum.*``' Intrinsic
11601 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
11602
11603 Syntax:
11604 """""""
11605
11606 This is an overloaded intrinsic. You can use ``llvm.maximum`` on any
11607 floating-point or vector of floating-point type. Not all targets support
11608 all types however.
11609
11610 ::
11611
11612 declare float @llvm.maximum.f32(float %Val0, float %Val1)
11613 declare double @llvm.maximum.f64(double %Val0, double %Val1)
11614 declare x86_fp80 @llvm.maximum.f80(x86_fp80 %Val0, x86_fp80 %Val1)
11615 declare fp128 @llvm.maximum.f128(fp128 %Val0, fp128 %Val1)
11616 declare ppc_fp128 @llvm.maximum.ppcf128(ppc_fp128 %Val0, ppc_fp128 %Val1)
11617
11618 Overview:
11619 """""""""
11620
11621 The '``llvm.maximum.*``' intrinsics return the maximum of the two
11622 arguments, propagating NaNs and treating -0.0 as less than +0.0.
11623
11624
11625 Arguments:
11626 """"""""""
11627
11628 The arguments and return value are floating-point numbers of the same
11629 type.
11630
11631 Semantics:
11632 """"""""""
11633 If either operand is a NaN, returns NaN. Otherwise returns the greater
11634 of the two arguments. -0.0 is considered to be less than +0.0 for this
11635 intrinsic. Note that these are the semantics specified in the draft of
11636 IEEE 754-2018.
11637
1156211638 '``llvm.copysign.*``' Intrinsic
1156311639 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1156411640
12421242 return (A.compare(B) == APFloat::cmpLessThan) ? B : A;
12431243 }
12441244
1245 /// Implements IEEE 754-2018 minimum semantics. Returns the smaller of 2
1246 /// arguments, propagating NaNs and treating -0 as less than +0.
1247 LLVM_READONLY
1248 inline APFloat minimum(const APFloat &A, const APFloat &B) {
1249 if (A.isNaN())
1250 return A;
1251 if (B.isNaN())
1252 return B;
1253 if (A.isZero() && B.isZero() && (A.isNegative() != B.isNegative()))
1254 return A.isNegative() ? A : B;
1255 return (B.compare(A) == APFloat::cmpLessThan) ? B : A;
1256 }
1257
1258 /// Implements IEEE 754-2018 maximum semantics. Returns the larger of 2
1259 /// arguments, propagating NaNs and treating -0 as less than +0.
1260 LLVM_READONLY
1261 inline APFloat maximum(const APFloat &A, const APFloat &B) {
1262 if (A.isNaN())
1263 return A;
1264 if (B.isNaN())
1265 return B;
1266 if (A.isZero() && B.isZero() && (A.isNegative() != B.isNegative()))
1267 return A.isNegative() ? B : A;
1268 return (A.compare(B) == APFloat::cmpLessThan) ? B : A;
1269 }
1270
12451271 } // namespace llvm
12461272
12471273 #undef APFLOAT_DISPATCH_ON_SEMANTICS
559559 ///
560560 /// The return value of (FMINNUM 0.0, -0.0) could be either 0.0 or -0.0.
561561 FMINNUM, FMAXNUM,
562 /// FMINNAN/FMAXNAN - Behave identically to FMINNUM/FMAXNUM, except that
563 /// when a single input is NaN, NaN is returned.
562 /// FMINNAN/FMAXNAN - NaN-propagating minimum/maximum that also treat -0.0
563 /// as less than 0.0. While FMINNUM/FMAXNUM follow IEEE 754-2008 semantics,
564 /// FMINNAN/FMAXNAN follow IEEE 754-2018 draft semantics.
564565 FMINNAN, FMAXNAN,
565566
566567 /// FSINCOS - Compute both fsin and fcos as a single operation.
704704 return CreateBinaryIntrinsic(Intrinsic::maxnum, LHS, RHS, nullptr, Name);
705705 }
706706
707 /// Create call to the minimum intrinsic.
708 CallInst *CreateMinimum(Value *LHS, Value *RHS, const Twine &Name = "") {
709 return CreateBinaryIntrinsic(Intrinsic::minimum, LHS, RHS, nullptr, Name);
710 }
711
712 /// Create call to the maximum intrinsic.
713 CallInst *CreateMaximum(Value *LHS, Value *RHS, const Twine &Name = "") {
714 return CreateBinaryIntrinsic(Intrinsic::maximum, LHS, RHS, nullptr, Name);
715 }
716
707717 private:
708718 /// Create a call to a masked intrinsic with given Id.
709719 CallInst *CreateMaskedIntrinsic(Intrinsic::ID Id, ArrayRef Ops,
449449 [IntrNoMem, IntrSpeculatable, Commutative]
450450 >;
451451 def int_maxnum : Intrinsic<[llvm_anyfloat_ty],
452 [LLVMMatchType<0>, LLVMMatchType<0>],
453 [IntrNoMem, IntrSpeculatable, Commutative]
454 >;
455 def int_minimum : Intrinsic<[llvm_anyfloat_ty],
456 [LLVMMatchType<0>, LLVMMatchType<0>],
457 [IntrNoMem, IntrSpeculatable, Commutative]
458 >;
459 def int_maximum : Intrinsic<[llvm_anyfloat_ty],
452460 [LLVMMatchType<0>, LLVMMatchType<0>],
453461 [IntrNoMem, IntrSpeculatable, Commutative]
454462 >;
55835583 getValue(I.getArgOperand(1))));
55845584 return nullptr;
55855585 }
5586 case Intrinsic::minimum:
5587 setValue(&I, DAG.getNode(ISD::FMINNAN, sdl,
5588 getValue(I.getArgOperand(0)).getValueType(),
5589 getValue(I.getArgOperand(0)),
5590 getValue(I.getArgOperand(1))));
5591 return nullptr;
5592 case Intrinsic::maximum:
5593 setValue(&I, DAG.getNode(ISD::FMAXNAN, sdl,
5594 getValue(I.getArgOperand(0)).getValueType(),
5595 getValue(I.getArgOperand(0)),
5596 getValue(I.getArgOperand(1))));
5597 return nullptr;
55865598 case Intrinsic::copysign:
55875599 setValue(&I, DAG.getNode(ISD::FCOPYSIGN, sdl,
55885600 getValue(I.getArgOperand(0)).getValueType(),
552552 EXPECT_EQ(2.0, maxnum(f2, f1).convertToDouble());
553553 EXPECT_EQ(1.0, maxnum(f1, nan).convertToDouble());
554554 EXPECT_EQ(1.0, maxnum(nan, f1).convertToDouble());
555 }
556
557 TEST(APFloatTest, Minimum) {
558 APFloat f1(1.0);
559 APFloat f2(2.0);
560 APFloat zp(0.0);
561 APFloat zn(-0.0);
562 APFloat nan = APFloat::getNaN(APFloat::IEEEdouble());
563
564 EXPECT_EQ(1.0, minimum(f1, f2).convertToDouble());
565 EXPECT_EQ(1.0, minimum(f2, f1).convertToDouble());
566 EXPECT_EQ(-0.0, minimum(zp, zn).convertToDouble());
567 EXPECT_EQ(-0.0, minimum(zn, zp).convertToDouble());
568 EXPECT_TRUE(std::isnan(minimum(f1, nan).convertToDouble()));
569 EXPECT_TRUE(std::isnan(minimum(nan, f1).convertToDouble()));
570 }
571
572 TEST(APFloatTest, Maximum) {
573 APFloat f1(1.0);
574 APFloat f2(2.0);
575 APFloat zp(0.0);
576 APFloat zn(-0.0);
577 APFloat nan = APFloat::getNaN(APFloat::IEEEdouble());
578
579 EXPECT_EQ(2.0, maximum(f1, f2).convertToDouble());
580 EXPECT_EQ(2.0, maximum(f2, f1).convertToDouble());
581 EXPECT_EQ(0.0, maximum(zp, zn).convertToDouble());
582 EXPECT_EQ(0.0, maximum(zn, zp).convertToDouble());
583 EXPECT_TRUE(std::isnan(maximum(f1, nan).convertToDouble()));
584 EXPECT_TRUE(std::isnan(maximum(nan, f1).convertToDouble()));
555585 }
556586
557587 TEST(APFloatTest, Denormal) {
6666 Call = Builder.CreateMaxNum(V, V);
6767 II = cast(Call);
6868 EXPECT_EQ(II->getIntrinsicID(), Intrinsic::maxnum);
69
70 Call = Builder.CreateMinimum(V, V);
71 II = cast(Call);
72 EXPECT_EQ(II->getIntrinsicID(), Intrinsic::minimum);
73
74 Call = Builder.CreateMaximum(V, V);
75 II = cast(Call);
76 EXPECT_EQ(II->getIntrinsicID(), Intrinsic::maximum);
6977
7078 Call = Builder.CreateIntrinsic(Intrinsic::readcyclecounter, {}, {});
7179 II = cast(Call);