Skip to content

Commit 0e5edc9

Browse files
committed
Add intrinsics for floating-point min and max
1 parent a318483 commit 0e5edc9

File tree

6 files changed

+82
-37
lines changed

6 files changed

+82
-37
lines changed

src/libcore/intrinsics.rs

+57
Original file line numberDiff line numberDiff line change
@@ -1051,6 +1051,19 @@ extern "rust-intrinsic" {
10511051
/// Returns the absolute value of an `f64`.
10521052
pub fn fabsf64(x: f64) -> f64;
10531053

1054+
/// Returns the minimum of two `f32` values.
1055+
#[cfg(not(bootstrap))]
1056+
pub fn minnumf32(x: f32, y: f32) -> f32;
1057+
/// Returns the minimum of two `f64` values.
1058+
#[cfg(not(bootstrap))]
1059+
pub fn minnumf64(x: f64, y: f64) -> f64;
1060+
/// Returns the maximum of two `f32` values.
1061+
#[cfg(not(bootstrap))]
1062+
pub fn maxnumf32(x: f32, y: f32) -> f32;
1063+
/// Returns the maximum of two `f64` values.
1064+
#[cfg(not(bootstrap))]
1065+
pub fn maxnumf64(x: f64, y: f64) -> f64;
1066+
10541067
/// Copies the sign from `y` to `x` for `f32` values.
10551068
pub fn copysignf32(x: f32, y: f32) -> f32;
10561069
/// Copies the sign from `y` to `x` for `f64` values.
@@ -1561,3 +1574,47 @@ pub unsafe fn copy<T>(src: *const T, dst: *mut T, count: usize) {
15611574
pub unsafe fn write_bytes<T>(dst: *mut T, val: u8, count: usize) {
15621575
real_intrinsics::write_bytes(dst, val, count)
15631576
}
1577+
1578+
// Simple bootstrap implementations of minnum/maxnum for stage0 compilation.
1579+
1580+
/// Returns the minimum of two `f32` values.
1581+
#[cfg(bootstrap)]
1582+
pub fn minnumf32(x: f32, y: f32) -> f32 {
1583+
// IEEE754 says: minNum(x, y) is the canonicalized number x if x < y, y if y < x, the
1584+
// canonicalized number if one operand is a number and the other a quiet NaN. Otherwise it
1585+
// is either x or y, canonicalized (this means results might differ among implementations).
1586+
// When either x or y is a signaling NaN, then the result is according to 6.2.
1587+
//
1588+
// Since we do not support sNaN in Rust yet, we do not need to handle them.
1589+
// FIXME(nagisa): due to https://bugs.llvm.org/show_bug.cgi?id=33303 we canonicalize by
1590+
// multiplying by 1.0. Should switch to the `canonicalize` when it works.
1591+
(if x < y || y != y { x } else { y }) * 1.0
1592+
}
1593+
1594+
/// Returns the minimum of two `f64` values.
1595+
#[cfg(bootstrap)]
1596+
pub fn minnumf64(x: f64, y: f64) -> f64 {
1597+
// Identical to the `f32` case.
1598+
(if x < y || y != y { x } else { y }) * 1.0
1599+
}
1600+
1601+
/// Returns the maximum of two `f32` values.
1602+
#[cfg(bootstrap)]
1603+
pub fn maxnumf32(x: f32, y: f32) -> f32 {
1604+
// IEEE754 says: maxNum(x, y) is the canonicalized number y if x < y, x if y < x, the
1605+
// canonicalized number if one operand is a number and the other a quiet NaN. Otherwise it
1606+
// is either x or y, canonicalized (this means results might differ among implementations).
1607+
// When either x or y is a signaling NaN, then the result is according to 6.2.
1608+
//
1609+
// Since we do not support sNaN in Rust yet, we do not need to handle them.
1610+
// FIXME(nagisa): due to https://bugs.llvm.org/show_bug.cgi?id=33303 we canonicalize by
1611+
// multiplying by 1.0. Should switch to the `canonicalize` when it works.
1612+
(if x < y || x != x { y } else { x }) * 1.0
1613+
}
1614+
1615+
/// Returns the maximum of two `f64` values.
1616+
#[cfg(bootstrap)]
1617+
pub fn maxnumf64(x: f64, y: f64) -> f64 {
1618+
// Identical to the `f32` case.
1619+
(if x < y || x != x { y } else { x }) * 1.0
1620+
}

src/libcore/num/f32.rs

+5-18
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@
77
88
#![stable(feature = "rust1", since = "1.0.0")]
99

10+
#[cfg(not(test))]
11+
use crate::intrinsics;
12+
1013
use crate::mem;
1114
use crate::num::FpCategory;
1215

@@ -372,15 +375,7 @@ impl f32 {
372375
#[stable(feature = "rust1", since = "1.0.0")]
373376
#[inline]
374377
pub fn max(self, other: f32) -> f32 {
375-
// IEEE754 says: maxNum(x, y) is the canonicalized number y if x < y, x if y < x, the
376-
// canonicalized number if one operand is a number and the other a quiet NaN. Otherwise it
377-
// is either x or y, canonicalized (this means results might differ among implementations).
378-
// When either x or y is a signalingNaN, then the result is according to 6.2.
379-
//
380-
// Since we do not support sNaN in Rust yet, we do not need to handle them.
381-
// FIXME(nagisa): due to https://bugs.llvm.org/show_bug.cgi?id=33303 we canonicalize by
382-
// multiplying by 1.0. Should switch to the `canonicalize` when it works.
383-
(if self.is_nan() || self < other { other } else { self }) * 1.0
378+
intrinsics::maxnumf32(self, other)
384379
}
385380

386381
/// Returns the minimum of the two numbers.
@@ -396,15 +391,7 @@ impl f32 {
396391
#[stable(feature = "rust1", since = "1.0.0")]
397392
#[inline]
398393
pub fn min(self, other: f32) -> f32 {
399-
// IEEE754 says: minNum(x, y) is the canonicalized number x if x < y, y if y < x, the
400-
// canonicalized number if one operand is a number and the other a quiet NaN. Otherwise it
401-
// is either x or y, canonicalized (this means results might differ among implementations).
402-
// When either x or y is a signalingNaN, then the result is according to 6.2.
403-
//
404-
// Since we do not support sNaN in Rust yet, we do not need to handle them.
405-
// FIXME(nagisa): due to https://bugs.llvm.org/show_bug.cgi?id=33303 we canonicalize by
406-
// multiplying by 1.0. Should switch to the `canonicalize` when it works.
407-
(if other.is_nan() || self < other { self } else { other }) * 1.0
394+
intrinsics::minnumf32(self, other)
408395
}
409396

410397
/// Raw transmutation to `u32`.

src/libcore/num/f64.rs

+5-18
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@
77
88
#![stable(feature = "rust1", since = "1.0.0")]
99

10+
#[cfg(not(test))]
11+
use crate::intrinsics;
12+
1013
use crate::mem;
1114
use crate::num::FpCategory;
1215

@@ -385,15 +388,7 @@ impl f64 {
385388
#[stable(feature = "rust1", since = "1.0.0")]
386389
#[inline]
387390
pub fn max(self, other: f64) -> f64 {
388-
// IEEE754 says: maxNum(x, y) is the canonicalized number y if x < y, x if y < x, the
389-
// canonicalized number if one operand is a number and the other a quiet NaN. Otherwise it
390-
// is either x or y, canonicalized (this means results might differ among implementations).
391-
// When either x or y is a signalingNaN, then the result is according to 6.2.
392-
//
393-
// Since we do not support sNaN in Rust yet, we do not need to handle them.
394-
// FIXME(nagisa): due to https://bugs.llvm.org/show_bug.cgi?id=33303 we canonicalize by
395-
// multiplying by 1.0. Should switch to the `canonicalize` when it works.
396-
(if self.is_nan() || self < other { other } else { self }) * 1.0
391+
intrinsics::maxnumf64(self, other)
397392
}
398393

399394
/// Returns the minimum of the two numbers.
@@ -409,15 +404,7 @@ impl f64 {
409404
#[stable(feature = "rust1", since = "1.0.0")]
410405
#[inline]
411406
pub fn min(self, other: f64) -> f64 {
412-
// IEEE754 says: minNum(x, y) is the canonicalized number x if x < y, y if y < x, the
413-
// canonicalized number if one operand is a number and the other a quiet NaN. Otherwise it
414-
// is either x or y, canonicalized (this means results might differ among implementations).
415-
// When either x or y is a signalingNaN, then the result is according to 6.2.
416-
//
417-
// Since we do not support sNaN in Rust yet, we do not need to handle them.
418-
// FIXME(nagisa): due to https://bugs.llvm.org/show_bug.cgi?id=33303 we canonicalize by
419-
// multiplying by 1.0. Should switch to the `canonicalize` when it works.
420-
(if other.is_nan() || self < other { self } else { other }) * 1.0
407+
intrinsics::minnumf64(self, other)
421408
}
422409

423410
/// Raw transmutation to `u64`.

src/librustc_codegen_llvm/context.rs

+5
Original file line numberDiff line numberDiff line change
@@ -645,6 +645,11 @@ impl CodegenCx<'b, 'tcx> {
645645
ifn!("llvm.fabs.v4f64", fn(t_v4f64) -> t_v4f64);
646646
ifn!("llvm.fabs.v8f64", fn(t_v8f64) -> t_v8f64);
647647

648+
ifn!("llvm.minnum.f32", fn(t_f32, t_f32) -> t_f32);
649+
ifn!("llvm.minnum.f64", fn(t_f64, t_f64) -> t_f64);
650+
ifn!("llvm.maxnum.f32", fn(t_f32, t_f32) -> t_f32);
651+
ifn!("llvm.maxnum.f64", fn(t_f64, t_f64) -> t_f64);
652+
648653
ifn!("llvm.floor.f32", fn(t_f32) -> t_f32);
649654
ifn!("llvm.floor.v2f32", fn(t_v2f32) -> t_v2f32);
650655
ifn!("llvm.floor.v4f32", fn(t_v4f32) -> t_v4f32);

src/librustc_codegen_llvm/intrinsic.rs

+4
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,10 @@ fn get_simple_intrinsic(cx: &CodegenCx<'ll, '_>, name: &str) -> Option<&'ll Valu
5555
"fmaf64" => "llvm.fma.f64",
5656
"fabsf32" => "llvm.fabs.f32",
5757
"fabsf64" => "llvm.fabs.f64",
58+
"minnumf32" => "llvm.minnum.f32",
59+
"minnumf64" => "llvm.minnum.f64",
60+
"maxnumf32" => "llvm.maxnum.f32",
61+
"maxnumf64" => "llvm.maxnum.f64",
5862
"copysignf32" => "llvm.copysign.f32",
5963
"copysignf64" => "llvm.copysign.f64",
6064
"floorf32" => "llvm.floor.f32",

src/librustc_typeck/check/intrinsic.rs

+6-1
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,8 @@ pub fn intrisic_operation_unsafety(intrinsic: &str) -> hir::Unsafety {
7070
"overflowing_add" | "overflowing_sub" | "overflowing_mul" |
7171
"saturating_add" | "saturating_sub" |
7272
"rotate_left" | "rotate_right" |
73-
"ctpop" | "ctlz" | "cttz" | "bswap" | "bitreverse"
73+
"ctpop" | "ctlz" | "cttz" | "bswap" | "bitreverse" |
74+
"minnumf32" | "minnumf64" | "maxnumf32" | "maxnumf64"
7475
=> hir::Unsafety::Normal,
7576
_ => hir::Unsafety::Unsafe,
7677
}
@@ -272,6 +273,10 @@ pub fn check_intrinsic_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
272273
}
273274
"fabsf32" => (0, vec![ tcx.types.f32 ], tcx.types.f32),
274275
"fabsf64" => (0, vec![ tcx.types.f64 ], tcx.types.f64),
276+
"minnumf32" => (0, vec![ tcx.types.f32, tcx.types.f32 ], tcx.types.f32),
277+
"minnumf64" => (0, vec![ tcx.types.f64, tcx.types.f64 ], tcx.types.f64),
278+
"maxnumf32" => (0, vec![ tcx.types.f32, tcx.types.f32 ], tcx.types.f32),
279+
"maxnumf64" => (0, vec![ tcx.types.f64, tcx.types.f64 ], tcx.types.f64),
275280
"copysignf32" => (0, vec![ tcx.types.f32, tcx.types.f32 ], tcx.types.f32),
276281
"copysignf64" => (0, vec![ tcx.types.f64, tcx.types.f64 ], tcx.types.f64),
277282
"floorf32" => (0, vec![ tcx.types.f32 ], tcx.types.f32),

0 commit comments

Comments
 (0)