From be681fefed254c06139ab055b07cfd6f8b30bacf Mon Sep 17 00:00:00 2001 From: Jules Bertholet Date: Fri, 25 Mar 2022 02:44:16 -0400 Subject: [PATCH] Add `round_ties_even` to `f32` and `f64` --- .../src/intrinsics/mod.rs | 2 ++ .../rustc_codegen_gcc/src/intrinsic/mod.rs | 2 ++ compiler/rustc_codegen_llvm/src/context.rs | 4 +++ compiler/rustc_codegen_llvm/src/intrinsic.rs | 2 ++ .../rustc_hir_analysis/src/check/intrinsic.rs | 2 ++ compiler/rustc_span/src/symbol.rs | 2 ++ library/core/src/intrinsics.rs | 16 ++++++++++ library/std/src/f32.rs | 31 +++++++++++++++++++ library/std/src/f32/tests.rs | 17 ++++++++++ library/std/src/f64.rs | 31 +++++++++++++++++++ library/std/src/f64/tests.rs | 17 ++++++++++ library/std/src/lib.rs | 1 + 12 files changed, 127 insertions(+) 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)]