about summary refs log tree commit diff
diff options
context:
space:
mode:
authorvarkor <github@varkor.com>2019-06-06 21:27:23 +0100
committervarkor <github@varkor.com>2019-06-06 21:27:23 +0100
commit0e5edc9f1611e5c13864e4f66a9e69ce7776ea91 (patch)
tree318c9ca1854557a859b08ef2687fe23a62c545bf
parenta31848350b1ccee5039c8e64fa3c6ea3edcbb1b0 (diff)
downloadrust-0e5edc9f1611e5c13864e4f66a9e69ce7776ea91.tar.gz
rust-0e5edc9f1611e5c13864e4f66a9e69ce7776ea91.zip
Add intrinsics for floating-point min and max
-rw-r--r--src/libcore/intrinsics.rs57
-rw-r--r--src/libcore/num/f32.rs23
-rw-r--r--src/libcore/num/f64.rs23
-rw-r--r--src/librustc_codegen_llvm/context.rs5
-rw-r--r--src/librustc_codegen_llvm/intrinsic.rs4
-rw-r--r--src/librustc_typeck/check/intrinsic.rs7
6 files changed, 82 insertions, 37 deletions
diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs
index 84867264e70..b609af16ffe 100644
--- a/src/libcore/intrinsics.rs
+++ b/src/libcore/intrinsics.rs
@@ -1051,6 +1051,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(bootstrap))]
+    pub fn minnumf32(x: f32, y: f32) -> f32;
+    /// Returns the minimum of two `f64` values.
+    #[cfg(not(bootstrap))]
+    pub fn minnumf64(x: f64, y: f64) -> f64;
+    /// Returns the maximum of two `f32` values.
+    #[cfg(not(bootstrap))]
+    pub fn maxnumf32(x: f32, y: f32) -> f32;
+    /// Returns the maximum of two `f64` values.
+    #[cfg(not(bootstrap))]
+    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.
@@ -1561,3 +1574,47 @@ pub unsafe fn copy<T>(src: *const T, dst: *mut T, count: usize) {
 pub unsafe fn write_bytes<T>(dst: *mut T, val: u8, count: usize) {
     real_intrinsics::write_bytes(dst, val, count)
 }
+
+// Simple bootstrap implementations of minnum/maxnum for stage0 compilation.
+
+/// Returns the minimum of two `f32` values.
+#[cfg(bootstrap)]
+pub 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 signaling NaN, 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(bootstrap)]
+pub 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(bootstrap)]
+pub 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 signaling NaN, 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(bootstrap)]
+pub 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 3f8d142c845..0bcd371b528 100644
--- a/src/libcore/num/f32.rs
+++ b/src/libcore/num/f32.rs
@@ -7,6 +7,9 @@
 
 #![stable(feature = "rust1", since = "1.0.0")]
 
+#[cfg(not(test))]
+use crate::intrinsics;
+
 use crate::mem;
 use crate::num::FpCategory;
 
@@ -372,15 +375,7 @@ impl f32 {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub 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.is_nan() || self < other { other } else { self }) * 1.0
+        intrinsics::maxnumf32(self, other)
     }
 
     /// Returns the minimum of the two numbers.
@@ -396,15 +391,7 @@ impl f32 {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub 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 other.is_nan() || self < other { self } else { other }) * 1.0
+        intrinsics::minnumf32(self, other)
     }
 
     /// Raw transmutation to `u32`.
diff --git a/src/libcore/num/f64.rs b/src/libcore/num/f64.rs
index 7f19101fe6e..4d4a2c9c5a9 100644
--- a/src/libcore/num/f64.rs
+++ b/src/libcore/num/f64.rs
@@ -7,6 +7,9 @@
 
 #![stable(feature = "rust1", since = "1.0.0")]
 
+#[cfg(not(test))]
+use crate::intrinsics;
+
 use crate::mem;
 use crate::num::FpCategory;
 
@@ -385,15 +388,7 @@ impl f64 {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub 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.is_nan() || self < other { other } else { self }) * 1.0
+        intrinsics::maxnumf64(self, other)
     }
 
     /// Returns the minimum of the two numbers.
@@ -409,15 +404,7 @@ impl f64 {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[inline]
     pub 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 other.is_nan() || self < other { self } else { other }) * 1.0
+        intrinsics::minnumf64(self, other)
     }
 
     /// Raw transmutation to `u64`.
diff --git a/src/librustc_codegen_llvm/context.rs b/src/librustc_codegen_llvm/context.rs
index ead9bad656d..2bc46334555 100644
--- a/src/librustc_codegen_llvm/context.rs
+++ b/src/librustc_codegen_llvm/context.rs
@@ -645,6 +645,11 @@ impl CodegenCx<'b, 'tcx> {
         ifn!("llvm.fabs.v4f64", fn(t_v4f64) -> t_v4f64);
         ifn!("llvm.fabs.v8f64", fn(t_v8f64) -> t_v8f64);
 
+        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.v2f32", fn(t_v2f32) -> t_v2f32);
         ifn!("llvm.floor.v4f32", fn(t_v4f32) -> t_v4f32);
diff --git a/src/librustc_codegen_llvm/intrinsic.rs b/src/librustc_codegen_llvm/intrinsic.rs
index f32dc431265..875f1d0940a 100644
--- a/src/librustc_codegen_llvm/intrinsic.rs
+++ b/src/librustc_codegen_llvm/intrinsic.rs
@@ -55,6 +55,10 @@ fn get_simple_intrinsic(cx: &CodegenCx<'ll, '_>, name: &str) -> Option<&'ll Valu
         "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 0b14ff1db59..11598ad4c9c 100644
--- a/src/librustc_typeck/check/intrinsic.rs
+++ b/src/librustc_typeck/check/intrinsic.rs
@@ -70,7 +70,8 @@ pub fn intrisic_operation_unsafety(intrinsic: &str) -> hir::Unsafety {
         "overflowing_add" | "overflowing_sub" | "overflowing_mul" |
         "saturating_add" | "saturating_sub" |
         "rotate_left" | "rotate_right" |
-        "ctpop" | "ctlz" | "cttz" | "bswap" | "bitreverse"
+        "ctpop" | "ctlz" | "cttz" | "bswap" | "bitreverse" |
+        "minnumf32" | "minnumf64" | "maxnumf32" | "maxnumf64"
         => hir::Unsafety::Normal,
         _ => hir::Unsafety::Unsafe,
     }
@@ -272,6 +273,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),