From 11e396b26ca3367030c14507238b3e9ba1bad599 Mon Sep 17 00:00:00 2001 From: Daan Sprenkels Date: Thu, 18 Feb 2021 16:31:04 +0100 Subject: [PATCH 1/3] Add roundeven float intrinsics --- compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs | 2 ++ compiler/rustc_codegen_llvm/src/context.rs | 2 ++ compiler/rustc_codegen_llvm/src/intrinsic.rs | 2 ++ compiler/rustc_span/src/symbol.rs | 2 ++ compiler/rustc_typeck/src/check/intrinsic.rs | 2 ++ 5 files changed, 10 insertions(+) diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs index 8946ac43bc65a..4d17d397528de 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs @@ -497,6 +497,8 @@ pub(crate) fn codegen_intrinsic_call<'tcx>( truncf64(flt) -> f64 => trunc, roundf32(flt) -> f32 => roundf, roundf64(flt) -> f64 => round, + roundevenf32(flt) -> f32 => roundevenf, + roundevenf64(flt) -> f64 => roundeven, // trigonometry sinf32(flt) -> f32 => sinf, diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index ee099f93258b7..7de740bfdd842 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -573,6 +573,8 @@ impl CodegenCx<'b, 'tcx> { 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); diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index 668daa52ed262..e635a97dd797a 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -68,6 +68,8 @@ fn get_simple_intrinsic(cx: &CodegenCx<'ll, '_>, name: Symbol) -> Option<&'ll Va sym::nearbyintf64 => "llvm.nearbyint.f64", sym::roundf32 => "llvm.round.f32", sym::roundf64 => "llvm.round.f64", + sym::roundevenf32 => "llvm.roundeven.f32", + sym::roundevenf64 => "llvm.roundeven.f64", _ => return None, }; Some(cx.get_intrinsic(&llvm_name)) diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 653d70b6cf244..4e60d0e22a788 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -931,6 +931,8 @@ symbols! { rlib, rotate_left, rotate_right, + roundevenf32, + roundevenf64, roundf32, roundf64, rt, diff --git a/compiler/rustc_typeck/src/check/intrinsic.rs b/compiler/rustc_typeck/src/check/intrinsic.rs index dedf96863eaf6..e0200ad29017c 100644 --- a/compiler/rustc_typeck/src/check/intrinsic.rs +++ b/compiler/rustc_typeck/src/check/intrinsic.rs @@ -247,6 +247,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)) From 69572c2976f5bd56503644aec0259ac3cae51941 Mon Sep 17 00:00:00 2001 From: Daan Sprenkels Date: Thu, 18 Feb 2021 19:54:13 +0100 Subject: [PATCH 2/3] Add round_to_even() to float types --- library/core/src/intrinsics.rs | 15 +++++++++++++++ library/std/src/f32.rs | 21 +++++++++++++++++++++ library/std/src/f64.rs | 21 +++++++++++++++++++++ 3 files changed, 57 insertions(+) diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index a9e2ef4251a16..319d3a99a45fa 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -1388,6 +1388,21 @@ 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 to the nearest even + /// integer. + /// + /// The version of this intrinsic in the standard libary is + /// [`f32::round`](../../std/primitive.f32.html#method.round_to_even) + #[cfg(not(bootstrap))] + pub fn roundevenf32(x: f32) -> f32; + /// Returns the nearest integer to an `f64`. Rounds half-way to the nearest even + /// integer. + /// + /// The version of this intrinsic in the standard libary is + /// [`f64::round`](../../std/primitive.f64.html#method.round_to_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 f51b2c2462166..2efb4cc7bb8cc 100644 --- a/library/std/src/f32.rs +++ b/library/std/src/f32.rs @@ -87,6 +87,27 @@ impl f32 { unsafe { intrinsics::roundf32(self) } } + /// Returns the nearest integer to a number. Round half-way cases to the + /// nearest even integer. + /// + /// # Examples + /// + /// ``` + /// # #![cfg_attr(not(bootstrap), feature(round_to_even))] + /// let f = 3.3_f32; + /// let g = -3.3_f32; + /// + /// assert_eq!(f.round_to_even(), 3.0); + /// assert_eq!(g.round_to_even(), -3.0); + /// ``` + #[cfg(not(bootstrap))] + #[must_use = "method returns a new number and does not mutate the original value"] + #[unstable(feature = "round_to_even", issue = "none")] + #[inline] + pub fn round_to_even(self) -> f32 { + unsafe { intrinsics::roundevenf32(self) } + } + /// Returns the integer part of a number. /// /// # Examples diff --git a/library/std/src/f64.rs b/library/std/src/f64.rs index 8c41e4486865c..5985601cc0843 100644 --- a/library/std/src/f64.rs +++ b/library/std/src/f64.rs @@ -87,6 +87,27 @@ impl f64 { unsafe { intrinsics::roundf64(self) } } + /// Returns the nearest integer to a number. Round half-way cases to the + /// nearest even integer. + /// + /// # Examples + /// + /// ``` + /// # #![cfg_attr(not(bootstrap), feature(round_to_even))] + /// let f = 3.3_f64; + /// let g = -3.3_f64; + /// + /// assert_eq!(f.round_to_even(), 3.0); + /// assert_eq!(g.round_to_even(), -3.0); + /// ``` + #[cfg(not(bootstrap))] + #[must_use = "method returns a new number and does not mutate the original value"] + #[unstable(feature = "round_to_even", issue = "none")] + #[inline] + pub fn round_to_even(self) -> f64 { + unsafe { intrinsics::roundevenf64(self) } + } + /// Returns the integer part of a number. /// /// # Examples From ddd8edc843a6d8bc8b64d6fff20a96c78165d2d4 Mon Sep 17 00:00:00 2001 From: Daan Sprenkels Date: Thu, 18 Feb 2021 20:14:53 +0100 Subject: [PATCH 3/3] Add tests for {f32,f64}::round_to_even() functions --- library/std/src/f32/tests.rs | 19 +++++++++++++++++++ library/std/src/f64/tests.rs | 19 +++++++++++++++++++ library/std/src/lib.rs | 1 + 3 files changed, 39 insertions(+) diff --git a/library/std/src/f32/tests.rs b/library/std/src/f32/tests.rs index 0d4b865f3392a..824762f460f6a 100644 --- a/library/std/src/f32/tests.rs +++ b/library/std/src/f32/tests.rs @@ -201,12 +201,31 @@ fn test_round() { assert_approx_eq!(1.3f32.round(), 1.0f32); assert_approx_eq!(1.5f32.round(), 2.0f32); assert_approx_eq!(1.7f32.round(), 2.0f32); + assert_approx_eq!(2.5f32.round(), 3.0f32); assert_approx_eq!(0.0f32.round(), 0.0f32); assert_approx_eq!((-0.0f32).round(), -0.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); assert_approx_eq!((-1.7f32).round(), -2.0f32); + assert_approx_eq!((-2.5f32).round(), -3.0f32); +} + +#[test] +#[cfg(not(bootstrap))] +fn test_round_to_even() { + assert_approx_eq!(1.0f32.round_to_even(), 1.0f32); + assert_approx_eq!(1.3f32.round_to_even(), 1.0f32); + assert_approx_eq!(1.5f32.round_to_even(), 2.0f32); + assert_approx_eq!(1.7f32.round_to_even(), 2.0f32); + assert_approx_eq!(2.5f32.round_to_even(), 2.0f32); + assert_approx_eq!(0.0f32.round_to_even(), 0.0f32); + assert_approx_eq!((-0.0f32).round_to_even(), -0.0f32); + assert_approx_eq!((-1.0f32).round_to_even(), -1.0f32); + assert_approx_eq!((-1.3f32).round_to_even(), -1.0f32); + assert_approx_eq!((-1.5f32).round_to_even(), -2.0f32); + assert_approx_eq!((-1.7f32).round_to_even(), -2.0f32); + assert_approx_eq!((-2.5f32).round_to_even(), -2.0f32); } #[test] diff --git a/library/std/src/f64/tests.rs b/library/std/src/f64/tests.rs index 5c163cfe90e0b..ec2f09fd3328a 100644 --- a/library/std/src/f64/tests.rs +++ b/library/std/src/f64/tests.rs @@ -203,12 +203,31 @@ fn test_round() { assert_approx_eq!(1.3f64.round(), 1.0f64); assert_approx_eq!(1.5f64.round(), 2.0f64); assert_approx_eq!(1.7f64.round(), 2.0f64); + assert_approx_eq!(2.5f64.round(), 3.0f64); assert_approx_eq!(0.0f64.round(), 0.0f64); assert_approx_eq!((-0.0f64).round(), -0.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); assert_approx_eq!((-1.7f64).round(), -2.0f64); + assert_approx_eq!((-2.5f64).round(), -3.0f64); +} + +#[test] +#[cfg(not(bootstrap))] +fn test_round_to_even() { + assert_approx_eq!(1.0f64.round_to_even(), 1.0f64); + assert_approx_eq!(1.3f64.round_to_even(), 1.0f64); + assert_approx_eq!(1.5f64.round_to_even(), 2.0f64); + assert_approx_eq!(1.7f64.round_to_even(), 2.0f64); + assert_approx_eq!(2.5f64.round_to_even(), 2.0f64); + assert_approx_eq!(0.0f64.round_to_even(), 0.0f64); + assert_approx_eq!((-0.0f64).round_to_even(), -0.0f64); + assert_approx_eq!((-1.0f64).round_to_even(), -1.0f64); + assert_approx_eq!((-1.3f64).round_to_even(), -1.0f64); + assert_approx_eq!((-1.5f64).round_to_even(), -2.0f64); + assert_approx_eq!((-1.7f64).round_to_even(), -2.0f64); + assert_approx_eq!((-2.5f64).round_to_even(), -2.0f64); } #[test] diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 16733b7ccd353..5cfd59354ceb8 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -302,6 +302,7 @@ #![feature(ptr_internals)] #![feature(raw)] #![feature(ready_macro)] +#![cfg_attr(not(bootstrap), feature(round_to_even))] #![feature(rustc_attrs)] #![feature(rustc_private)] #![feature(shrink_to)]