about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs4
-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.rs19
-rw-r--r--library/std/src/f32.rs30
-rw-r--r--library/std/src/f32/tests.rs16
-rw-r--r--library/std/src/f64.rs30
-rw-r--r--library/std/src/f64/tests.rs16
-rw-r--r--library/std/src/lib.rs1
12 files changed, 128 insertions, 0 deletions
diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
index e74aabf2fcb..24f8d5e464e 100644
--- a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
+++ b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
@@ -281,8 +281,12 @@ fn codegen_float_intrinsic_call<'tcx>(
         sym::ceilf64 => ("ceil", 1, fx.tcx.types.f64),
         sym::truncf32 => ("truncf", 1, fx.tcx.types.f32),
         sym::truncf64 => ("trunc", 1, fx.tcx.types.f64),
+        sym::rintf32 => ("rintf", 1, fx.tcx.types.f32),
+        sym::rintf64 => ("rint", 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 3d29968d5d6..f0d729d4779 100644
--- a/compiler/rustc_codegen_llvm/src/context.rs
+++ b/compiler/rustc_codegen_llvm/src/context.rs
@@ -735,9 +735,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 39afb4af6f6..9c921989ca9 100644
--- a/compiler/rustc_codegen_llvm/src/intrinsic.rs
+++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs
@@ -71,6 +71,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 054284cced5..20b6561f8b2 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 6272bf7f25e..4e626fd9f30 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -1197,6 +1197,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 18a90599c4d..c6321587adc 100644
--- a/library/core/src/intrinsics.rs
+++ b/library/core/src/intrinsics.rs
@@ -1585,9 +1585,15 @@ extern "rust-intrinsic" {
 
     /// Returns the nearest integer to an `f32`. May raise an inexact floating-point exception
     /// if the argument is not an integer.
+    ///
+    /// The stabilized version of this intrinsic is
+    /// [`f32::round_ties_even`](../../std/primitive.f32.html#method.round_ties_even)
     pub fn rintf32(x: f32) -> f32;
     /// Returns the nearest integer to an `f64`. May raise an inexact floating-point exception
     /// if the argument is not an integer.
+    ///
+    /// The stabilized version of this intrinsic is
+    /// [`f64::round_ties_even`](../../std/primitive.f64.html#method.round_ties_even)
     pub fn rintf64(x: f64) -> f64;
 
     /// Returns the nearest integer to an `f32`.
@@ -1610,6 +1616,19 @@ 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.
+    ///
+    /// This intrinsic does not have a stable counterpart.
+    #[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.
+    ///
+    /// This intrinsic does not have a stable counterpart.
+    #[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 6b1f0cba82d..c7c33678fd3 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,32 @@ 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);
+    /// ```
+    #[rustc_allow_incoherent_impl]
+    #[must_use = "method returns a new number and does not mutate the original value"]
+    #[unstable(feature = "round_ties_even", issue = "96710")]
+    #[inline]
+    pub fn round_ties_even(self) -> f32 {
+        unsafe { intrinsics::rintf32(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..e949def00bb 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);
@@ -222,6 +223,21 @@ fn test_round() {
 }
 
 #[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);
     assert_approx_eq!(1.3f32.trunc(), 1.0f32);
diff --git a/library/std/src/f64.rs b/library/std/src/f64.rs
index 16359766b51..b1faa670307 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,32 @@ 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);
+    /// ```
+    #[rustc_allow_incoherent_impl]
+    #[must_use = "method returns a new number and does not mutate the original value"]
+    #[unstable(feature = "round_ties_even", issue = "96710")]
+    #[inline]
+    pub fn round_ties_even(self) -> f64 {
+        unsafe { intrinsics::rintf64(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..53d351cceef 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);
@@ -212,6 +213,21 @@ fn test_round() {
 }
 
 #[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);
     assert_approx_eq!(1.3f64.trunc(), 1.0f64);
diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs
index b62f3ad29d3..7837dd276d2 100644
--- a/library/std/src/lib.rs
+++ b/library/std/src/lib.rs
@@ -304,6 +304,7 @@
 #![feature(provide_any)]
 #![feature(ptr_as_uninit)]
 #![feature(raw_os_nonzero)]
+#![feature(round_ties_even)]
 #![feature(slice_internals)]
 #![feature(slice_ptr_get)]
 #![feature(std_internals)]