diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index f1e51e995c238..ec6eeb2ad1ed3 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -1142,6 +1142,19 @@ extern "rust-intrinsic" { /// Returns the absolute value of an `f64`. pub fn fabsf64(x: f64) -> f64; + /// Returns the minimum of two `f32` values. + #[cfg(not(stage0))] + pub fn minnumf32(x: f32, y: f32) -> f32; + /// Returns the minimum of two `f64` values. + #[cfg(not(stage0))] + pub fn minnumf64(x: f64, y: f64) -> f64; + /// Returns the maximum of two `f32` values. + #[cfg(not(stage0))] + pub fn maxnumf32(x: f32, y: f32) -> f32; + /// Returns the maximum of two `f64` values. + #[cfg(not(stage0))] + pub fn maxnumf64(x: f64, y: f64) -> f64; + /// Copies the sign from `y` to `x` for `f32` values. pub fn copysignf32(x: f32, y: f32) -> f32; /// Copies the sign from `y` to `x` for `f64` values. @@ -1393,3 +1406,44 @@ extern "rust-intrinsic" { #[cfg(not(stage0))] pub fn nontemporal_store(ptr: *mut T, val: T); } + +// Simple bootstrap implementations for stage0 compilation + +/// Returns the minimum of two `f32` values. +#[cfg(stage0)] +pub unsafe fn minnumf32(x: f32, y: f32) -> f32 { + // IEEE754 says: minNum(x, y) is the canonicalized number x if x < y, y if y < x, the + // canonicalized number if one operand is a number and the other a quiet NaN. Otherwise it + // is either x or y, canonicalized (this means results might differ among implementations). + // When either x or y is a signalingNaN, then the result is according to 6.2. + // + // Since we do not support sNaN in Rust yet, we do not need to handle them. + // FIXME(nagisa): due to https://bugs.llvm.org/show_bug.cgi?id=33303 we canonicalize by + // multiplying by 1.0. Should switch to the `canonicalize` when it works. + (if x < y || y != y { x } else { y }) * 1.0 +} +/// Returns the minimum of two `f64` values. +#[cfg(stage0)] +pub unsafe fn minnumf64(x: f64, y: f64) -> f64 { + // Identical to the `f32` case. + (if x < y || y != y { x } else { y }) * 1.0 +} +/// Returns the maximum of two `f32` values. +#[cfg(stage0)] +pub unsafe fn maxnumf32(x: f32, y: f32) -> f32 { + // IEEE754 says: maxNum(x, y) is the canonicalized number y if x < y, x if y < x, the + // canonicalized number if one operand is a number and the other a quiet NaN. Otherwise it + // is either x or y, canonicalized (this means results might differ among implementations). + // When either x or y is a signalingNaN, then the result is according to 6.2. + // + // Since we do not support sNaN in Rust yet, we do not need to handle them. + // FIXME(nagisa): due to https://bugs.llvm.org/show_bug.cgi?id=33303 we canonicalize by + // multiplying by 1.0. Should switch to the `canonicalize` when it works. + (if x < y || x != x { y } else { x }) * 1.0 +} +/// Returns the maximum of two `f64` values. +#[cfg(stage0)] +pub unsafe fn maxnumf64(x: f64, y: f64) -> f64 { + // Identical to the `f32` case. + (if x < y || x != x { y } else { x }) * 1.0 +} diff --git a/src/libcore/num/f32.rs b/src/libcore/num/f32.rs index 43d38926c9718..ba84718fa137c 100644 --- a/src/libcore/num/f32.rs +++ b/src/libcore/num/f32.rs @@ -250,28 +250,12 @@ impl Float for f32 { /// Returns the maximum of the two numbers. #[inline] fn max(self, other: f32) -> f32 { - // IEEE754 says: maxNum(x, y) is the canonicalized number y if x < y, x if y < x, the - // canonicalized number if one operand is a number and the other a quiet NaN. Otherwise it - // is either x or y, canonicalized (this means results might differ among implementations). - // When either x or y is a signalingNaN, then the result is according to 6.2. - // - // Since we do not support sNaN in Rust yet, we do not need to handle them. - // FIXME(nagisa): due to https://bugs.llvm.org/show_bug.cgi?id=33303 we canonicalize by - // multiplying by 1.0. Should switch to the `canonicalize` when it works. - (if self < other || self.is_nan() { other } else { self }) * 1.0 + unsafe { intrinsics::maxnumf32(self, other) } } /// Returns the minimum of the two numbers. #[inline] fn min(self, other: f32) -> f32 { - // IEEE754 says: minNum(x, y) is the canonicalized number x if x < y, y if y < x, the - // canonicalized number if one operand is a number and the other a quiet NaN. Otherwise it - // is either x or y, canonicalized (this means results might differ among implementations). - // When either x or y is a signalingNaN, then the result is according to 6.2. - // - // Since we do not support sNaN in Rust yet, we do not need to handle them. - // FIXME(nagisa): due to https://bugs.llvm.org/show_bug.cgi?id=33303 we canonicalize by - // multiplying by 1.0. Should switch to the `canonicalize` when it works. - (if self < other || other.is_nan() { self } else { other }) * 1.0 + unsafe { intrinsics::minnumf32(self, other) } } } diff --git a/src/libcore/num/f64.rs b/src/libcore/num/f64.rs index 4ff80a2f05d41..f50537b2cbe07 100644 --- a/src/libcore/num/f64.rs +++ b/src/libcore/num/f64.rs @@ -248,28 +248,12 @@ impl Float for f64 { /// Returns the maximum of the two numbers. #[inline] fn max(self, other: f64) -> f64 { - // IEEE754 says: maxNum(x, y) is the canonicalized number y if x < y, x if y < x, the - // canonicalized number if one operand is a number and the other a quiet NaN. Otherwise it - // is either x or y, canonicalized (this means results might differ among implementations). - // When either x or y is a signalingNaN, then the result is according to 6.2. - // - // Since we do not support sNaN in Rust yet, we do not need to handle them. - // FIXME(nagisa): due to https://bugs.llvm.org/show_bug.cgi?id=33303 we canonicalize by - // multiplying by 1.0. Should switch to the `canonicalize` when it works. - (if self < other || self.is_nan() { other } else { self }) * 1.0 + unsafe { intrinsics::maxnumf64(self, other) } } /// Returns the minimum of the two numbers. #[inline] fn min(self, other: f64) -> f64 { - // IEEE754 says: minNum(x, y) is the canonicalized number x if x < y, y if y < x, the - // canonicalized number if one operand is a number and the other a quiet NaN. Otherwise it - // is either x or y, canonicalized (this means results might differ among implementations). - // When either x or y is a signalingNaN, then the result is according to 6.2. - // - // Since we do not support sNaN in Rust yet, we do not need to handle them. - // FIXME(nagisa): due to https://bugs.llvm.org/show_bug.cgi?id=33303 we canonicalize by - // multiplying by 1.0. Should switch to the `canonicalize` when it works. - (if self < other || other.is_nan() { self } else { other }) * 1.0 + unsafe { intrinsics::minnumf64(self, other) } } } diff --git a/src/librustc_trans/context.rs b/src/librustc_trans/context.rs index d5e71062f74d7..f92bb0767975f 100644 --- a/src/librustc_trans/context.rs +++ b/src/librustc_trans/context.rs @@ -782,6 +782,11 @@ fn declare_intrinsic(ccx: &CrateContext, key: &str) -> Option { ifn!("llvm.fabs.f32", fn(t_f32) -> t_f32); ifn!("llvm.fabs.f64", fn(t_f64) -> t_f64); + ifn!("llvm.minnum.f32", fn(t_f32, t_f32) -> t_f32); + ifn!("llvm.minnum.f64", fn(t_f64, t_f64) -> t_f64); + ifn!("llvm.maxnum.f32", fn(t_f32, t_f32) -> t_f32); + ifn!("llvm.maxnum.f64", fn(t_f64, t_f64) -> t_f64); + ifn!("llvm.floor.f32", fn(t_f32) -> t_f32); ifn!("llvm.floor.f64", fn(t_f64) -> t_f64); ifn!("llvm.ceil.f32", fn(t_f32) -> t_f32); diff --git a/src/librustc_trans/intrinsic.rs b/src/librustc_trans/intrinsic.rs index 3cd60e7f1bc7f..4584745745fb1 100644 --- a/src/librustc_trans/intrinsic.rs +++ b/src/librustc_trans/intrinsic.rs @@ -61,6 +61,10 @@ fn get_simple_intrinsic(ccx: &CrateContext, name: &str) -> Option { "fmaf64" => "llvm.fma.f64", "fabsf32" => "llvm.fabs.f32", "fabsf64" => "llvm.fabs.f64", + "minnumf32" => "llvm.minnum.f32", + "minnumf64" => "llvm.minnum.f64", + "maxnumf32" => "llvm.maxnum.f32", + "maxnumf64" => "llvm.maxnum.f64", "copysignf32" => "llvm.copysign.f32", "copysignf64" => "llvm.copysign.f64", "floorf32" => "llvm.floor.f32", diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs index 23243c3ad66c0..0cf472335e2ac 100644 --- a/src/librustc_typeck/check/intrinsic.rs +++ b/src/librustc_typeck/check/intrinsic.rs @@ -255,6 +255,10 @@ pub fn check_intrinsic_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } "fabsf32" => (0, vec![ tcx.types.f32 ], tcx.types.f32), "fabsf64" => (0, vec![ tcx.types.f64 ], tcx.types.f64), + "minnumf32" => (0, vec![ tcx.types.f32, tcx.types.f32 ], tcx.types.f32), + "minnumf64" => (0, vec![ tcx.types.f64, tcx.types.f64 ], tcx.types.f64), + "maxnumf32" => (0, vec![ tcx.types.f32, tcx.types.f32 ], tcx.types.f32), + "maxnumf64" => (0, vec![ tcx.types.f64, tcx.types.f64 ], tcx.types.f64), "copysignf32" => (0, vec![ tcx.types.f32, tcx.types.f32 ], tcx.types.f32), "copysignf64" => (0, vec![ tcx.types.f64, tcx.types.f64 ], tcx.types.f64), "floorf32" => (0, vec![ tcx.types.f32 ], tcx.types.f32),