about summary refs log tree commit diff
diff options
context:
space:
mode:
authorJules Bertholet <jules.bertholet@gmail.com>2022-03-25 02:44:16 -0400
committerJules Bertholet <julesbertholet@quoi.xyz>2022-12-11 01:20:17 -0500
commitbe681fefed254c06139ab055b07cfd6f8b30bacf (patch)
treeb0d913a5c11a472075da00e42463e81ab7ba090a
parente1c91213ff80af5b87a197b784b40bcbc8cf3add (diff)
downloadrust-be681fefed254c06139ab055b07cfd6f8b30bacf.tar.gz
rust-be681fefed254c06139ab055b07cfd6f8b30bacf.zip
Add `round_ties_even` to `f32` and `f64`
-rw-r--r--compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs2
-rw-r--r--compiler/rustc_codegen_gcc/src/intrinsic/mod.rs2
-rw-r--r--compiler/rustc_codegen_llvm/src/context.rs4
-rw-r--r--compiler/rustc_codegen_llvm/src/intrinsic.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/check/intrinsic.rs2
-rw-r--r--compiler/rustc_span/src/symbol.rs2
-rw-r--r--library/core/src/intrinsics.rs16
-rw-r--r--library/std/src/f32.rs31
-rw-r--r--library/std/src/f32/tests.rs17
-rw-r--r--library/std/src/f64.rs31
-rw-r--r--library/std/src/f64/tests.rs17
-rw-r--r--library/std/src/lib.rs1
12 files changed, 127 insertions, 0 deletions
diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
index 0302b843aa2..4851c3fdcb7 100644
--- a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
+++ b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
@@ -297,6 +297,8 @@ fn codegen_float_intrinsic_call<'tcx>(
         sym::truncf64 => ("trunc", 1, fx.tcx.types.f64),
         sym::roundf32 => ("roundf", 1, fx.tcx.types.f32),
         sym::roundf64 => ("round", 1, fx.tcx.types.f64),
+        sym::roundevenf32 => ("roundevenf", 1, fx.tcx.types.f32),
+        sym::roundevenf64 => ("roundeven", 1, fx.tcx.types.f64),
         sym::sinf32 => ("sinf", 1, fx.tcx.types.f32),
         sym::sinf64 => ("sin", 1, fx.tcx.types.f64),
         sym::cosf32 => ("cosf", 1, fx.tcx.types.f32),
diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs
index 49be6c649e6..35e650c65a0 100644
--- a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs
+++ b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs
@@ -68,6 +68,8 @@ fn get_simple_intrinsic<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, name: Symbol) ->
         sym::nearbyintf64 => "nearbyint",
         sym::roundf32 => "roundf",
         sym::roundf64 => "round",
+        sym::roundevenf32 => "roundevenf",
+        sym::roundevenf64 => "roundeven",
         sym::abort => "abort",
         _ => return None,
     };
diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs
index aa1735f38ac..697f5b7b644 100644
--- a/compiler/rustc_codegen_llvm/src/context.rs
+++ b/compiler/rustc_codegen_llvm/src/context.rs
@@ -745,9 +745,13 @@ impl<'ll> CodegenCx<'ll, '_> {
 
         ifn!("llvm.copysign.f32", fn(t_f32, t_f32) -> t_f32);
         ifn!("llvm.copysign.f64", fn(t_f64, t_f64) -> t_f64);
+
         ifn!("llvm.round.f32", fn(t_f32) -> t_f32);
         ifn!("llvm.round.f64", fn(t_f64) -> t_f64);
 
+        ifn!("llvm.roundeven.f32", fn(t_f32) -> t_f32);
+        ifn!("llvm.roundeven.f64", fn(t_f64) -> t_f64);
+
         ifn!("llvm.rint.f32", fn(t_f32) -> t_f32);
         ifn!("llvm.rint.f64", fn(t_f64) -> t_f64);
         ifn!("llvm.nearbyint.f32", fn(t_f32) -> t_f32);
diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs
index 2f5dd519b26..4c0b0cde3f0 100644
--- a/compiler/rustc_codegen_llvm/src/intrinsic.rs
+++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs
@@ -72,6 +72,8 @@ fn get_simple_intrinsic<'ll>(
         sym::roundf32 => "llvm.round.f32",
         sym::roundf64 => "llvm.round.f64",
         sym::ptr_mask => "llvm.ptrmask",
+        sym::roundevenf32 => "llvm.roundeven.f32",
+        sym::roundevenf64 => "llvm.roundeven.f64",
         _ => return None,
     };
     Some(cx.get_intrinsic(llvm_name))
diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
index 69e54b41d4c..afbcc517751 100644
--- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs
+++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
@@ -300,6 +300,8 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
             sym::nearbyintf64 => (0, vec![tcx.types.f64], tcx.types.f64),
             sym::roundf32 => (0, vec![tcx.types.f32], tcx.types.f32),
             sym::roundf64 => (0, vec![tcx.types.f64], tcx.types.f64),
+            sym::roundevenf32 => (0, vec![tcx.types.f32], tcx.types.f32),
+            sym::roundevenf64 => (0, vec![tcx.types.f64], tcx.types.f64),
 
             sym::volatile_load | sym::unaligned_volatile_load => {
                 (1, vec![tcx.mk_imm_ptr(param(0))], param(0))
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 1fcf8c7a8bf..6f983f07fc1 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -1179,6 +1179,8 @@ symbols! {
         rlib,
         rotate_left,
         rotate_right,
+        roundevenf32,
+        roundevenf64,
         roundf32,
         roundf64,
         rt,
diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs
index 7ed7d767f2f..e331dfff6fd 100644
--- a/library/core/src/intrinsics.rs
+++ b/library/core/src/intrinsics.rs
@@ -1613,6 +1613,22 @@ extern "rust-intrinsic" {
     /// [`f64::round`](../../std/primitive.f64.html#method.round)
     pub fn roundf64(x: f64) -> f64;
 
+    /// Returns the nearest integer to an `f32`. Rounds half-way cases to the number
+    /// with an even least significant digit.
+    ///
+    /// The stabilized version of this intrinsic is
+    /// [`f32::round_ties_even`](../../std/primitive.f32.html#method.round_ties_even)
+    #[cfg(not(bootstrap))]
+    pub fn roundevenf32(x: f32) -> f32;
+
+    /// Returns the nearest integer to an `f64`. Rounds half-way cases to the number
+    /// with an even least significant digit.
+    ///
+    /// The stabilized version of this intrinsic is
+    /// [`f64::round_ties_even`](../../std/primitive.f64.html#method.round_ties_even)
+    #[cfg(not(bootstrap))]
+    pub fn roundevenf64(x: f64) -> f64;
+
     /// Float addition that allows optimizations based on algebraic rules.
     /// May assume inputs are finite.
     ///
diff --git a/library/std/src/f32.rs b/library/std/src/f32.rs
index 4e300762463..a2c65e02577 100644
--- a/library/std/src/f32.rs
+++ b/library/std/src/f32.rs
@@ -78,10 +78,14 @@ impl f32 {
     /// let f = 3.3_f32;
     /// let g = -3.3_f32;
     /// let h = -3.7_f32;
+    /// let i = 3.5_f32;
+    /// let j = 4.5_f32;
     ///
     /// assert_eq!(f.round(), 3.0);
     /// assert_eq!(g.round(), -3.0);
     /// assert_eq!(h.round(), -4.0);
+    /// assert_eq!(i.round(), 4.0);
+    /// assert_eq!(j.round(), 5.0);
     /// ```
     #[rustc_allow_incoherent_impl]
     #[must_use = "method returns a new number and does not mutate the original value"]
@@ -91,6 +95,33 @@ impl f32 {
         unsafe { intrinsics::roundf32(self) }
     }
 
+    /// Returns the nearest integer to a number. Rounds half-way cases to the number
+    /// with an even least significant digit.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(round_ties_even)]
+    ///
+    /// let f = 3.3_f32;
+    /// let g = -3.3_f32;
+    /// let h = 3.5_f32;
+    /// let i = 4.5_f32;
+    ///
+    /// assert_eq!(f.round_ties_even(), 3.0);
+    /// assert_eq!(g.round_ties_even(), -3.0);
+    /// assert_eq!(h.round_ties_even(), 4.0);
+    /// assert_eq!(i.round_ties_even(), 4.0);
+    /// ```
+    #[cfg(not(bootstrap))]
+    #[cfg_attr(not(bootstrap), rustc_allow_incoherent_impl)]
+    #[must_use = "method returns a new number and does not mutate the original value"]
+    #[unstable(feature = "round_ties_even", issue = "none")]
+    #[inline]
+    pub fn round_ties_even(self) -> f32 {
+        unsafe { intrinsics::roundevenf32(self) }
+    }
+
     /// Returns the integer part of `self`.
     /// This means that non-integer numbers are always truncated towards zero.
     ///
diff --git a/library/std/src/f32/tests.rs b/library/std/src/f32/tests.rs
index 6ee295de616..d4671243f47 100644
--- a/library/std/src/f32/tests.rs
+++ b/library/std/src/f32/tests.rs
@@ -209,6 +209,7 @@ fn test_ceil() {
 
 #[test]
 fn test_round() {
+    assert_approx_eq!(2.5f32.round(), 3.0f32);
     assert_approx_eq!(1.0f32.round(), 1.0f32);
     assert_approx_eq!(1.3f32.round(), 1.0f32);
     assert_approx_eq!(1.5f32.round(), 2.0f32);
@@ -221,6 +222,22 @@ fn test_round() {
     assert_approx_eq!((-1.7f32).round(), -2.0f32);
 }
 
+#[cfg(not(bootstrap))]
+#[test]
+fn test_round_ties_even() {
+    assert_approx_eq!(2.5f32.round_ties_even(), 2.0f32);
+    assert_approx_eq!(1.0f32.round_ties_even(), 1.0f32);
+    assert_approx_eq!(1.3f32.round_ties_even(), 1.0f32);
+    assert_approx_eq!(1.5f32.round_ties_even(), 2.0f32);
+    assert_approx_eq!(1.7f32.round_ties_even(), 2.0f32);
+    assert_approx_eq!(0.0f32.round_ties_even(), 0.0f32);
+    assert_approx_eq!((-0.0f32).round_ties_even(), -0.0f32);
+    assert_approx_eq!((-1.0f32).round_ties_even(), -1.0f32);
+    assert_approx_eq!((-1.3f32).round_ties_even(), -1.0f32);
+    assert_approx_eq!((-1.5f32).round_ties_even(), -2.0f32);
+    assert_approx_eq!((-1.7f32).round_ties_even(), -2.0f32);
+}
+
 #[test]
 fn test_trunc() {
     assert_approx_eq!(1.0f32.trunc(), 1.0f32);
diff --git a/library/std/src/f64.rs b/library/std/src/f64.rs
index ec67fdad4f7..85dfb102c7d 100644
--- a/library/std/src/f64.rs
+++ b/library/std/src/f64.rs
@@ -78,10 +78,14 @@ impl f64 {
     /// let f = 3.3_f64;
     /// let g = -3.3_f64;
     /// let h = -3.7_f64;
+    /// let i = 3.5_f64;
+    /// let j = 4.5_f64;
     ///
     /// assert_eq!(f.round(), 3.0);
     /// assert_eq!(g.round(), -3.0);
     /// assert_eq!(h.round(), -4.0);
+    /// assert_eq!(i.round(), 4.0);
+    /// assert_eq!(j.round(), 5.0);
     /// ```
     #[rustc_allow_incoherent_impl]
     #[must_use = "method returns a new number and does not mutate the original value"]
@@ -91,6 +95,33 @@ impl f64 {
         unsafe { intrinsics::roundf64(self) }
     }
 
+    /// Returns the nearest integer to a number. Rounds half-way cases to the number
+    /// with an even least significant digit.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(round_ties_even)]
+    ///
+    /// let f = 3.3_f64;
+    /// let g = -3.3_f64;
+    /// let h = 3.5_f64;
+    /// let i = 4.5_f64;
+    ///
+    /// assert_eq!(f.round_ties_even(), 3.0);
+    /// assert_eq!(g.round_ties_even(), -3.0);
+    /// assert_eq!(h.round_ties_even(), 4.0);
+    /// assert_eq!(i.round_ties_even(), 4.0);
+    /// ```
+    #[cfg(not(bootstrap))]
+    #[cfg_attr(not(bootstrap), rustc_allow_incoherent_impl)]
+    #[must_use = "method returns a new number and does not mutate the original value"]
+    #[unstable(feature = "round_ties_even", issue = "none")]
+    #[inline]
+    pub fn round_ties_even(self) -> f64 {
+        unsafe { intrinsics::roundevenf64(self) }
+    }
+
     /// Returns the integer part of `self`.
     /// This means that non-integer numbers are always truncated towards zero.
     ///
diff --git a/library/std/src/f64/tests.rs b/library/std/src/f64/tests.rs
index 5b039d445ce..2f84ff910f5 100644
--- a/library/std/src/f64/tests.rs
+++ b/library/std/src/f64/tests.rs
@@ -199,6 +199,7 @@ fn test_ceil() {
 
 #[test]
 fn test_round() {
+    assert_approx_eq!(2.5f64.round(), 3.0f64);
     assert_approx_eq!(1.0f64.round(), 1.0f64);
     assert_approx_eq!(1.3f64.round(), 1.0f64);
     assert_approx_eq!(1.5f64.round(), 2.0f64);
@@ -211,6 +212,22 @@ fn test_round() {
     assert_approx_eq!((-1.7f64).round(), -2.0f64);
 }
 
+#[cfg(not(bootstrap))]
+#[test]
+fn test_round_ties_even() {
+    assert_approx_eq!(2.5f64.round_ties_even(), 2.0f64);
+    assert_approx_eq!(1.0f64.round_ties_even(), 1.0f64);
+    assert_approx_eq!(1.3f64.round_ties_even(), 1.0f64);
+    assert_approx_eq!(1.5f64.round_ties_even(), 2.0f64);
+    assert_approx_eq!(1.7f64.round_ties_even(), 2.0f64);
+    assert_approx_eq!(0.0f64.round_ties_even(), 0.0f64);
+    assert_approx_eq!((-0.0f64).round_ties_even(), -0.0f64);
+    assert_approx_eq!((-1.0f64).round_ties_even(), -1.0f64);
+    assert_approx_eq!((-1.3f64).round_ties_even(), -1.0f64);
+    assert_approx_eq!((-1.5f64).round_ties_even(), -2.0f64);
+    assert_approx_eq!((-1.7f64).round_ties_even(), -2.0f64);
+}
+
 #[test]
 fn test_trunc() {
     assert_approx_eq!(1.0f64.trunc(), 1.0f64);
diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs
index 65d4c3c891e..02814d42dd3 100644
--- a/library/std/src/lib.rs
+++ b/library/std/src/lib.rs
@@ -307,6 +307,7 @@
 #![feature(provide_any)]
 #![feature(ptr_as_uninit)]
 #![feature(raw_os_nonzero)]
+#![cfg_attr(not(bootstrap), feature(round_ties_even))]
 #![feature(slice_internals)]
 #![feature(slice_ptr_get)]
 #![feature(std_internals)]