From bf2d171b1a29849b745cfd0dd6409c0c2b3c0cea Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 22 Jan 2025 09:06:26 +0000 Subject: [PATCH 1/2] Add a generic version of `rint` Use this to implement `rint` and `rintf`. --- .../libm/etc/function-definitions.json | 2 + .../libm/src/math/generic/mod.rs | 2 + .../libm/src/math/generic/rint.rs | 72 +++++++++++++++++++ .../compiler-builtins/libm/src/math/rint.rs | 48 +------------ .../compiler-builtins/libm/src/math/rintf.rs | 48 +------------ 5 files changed, 78 insertions(+), 94 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/generic/rint.rs diff --git a/library/compiler-builtins/libm/etc/function-definitions.json b/library/compiler-builtins/libm/etc/function-definitions.json index eef176fb57c8..86b0882927cc 100644 --- a/library/compiler-builtins/libm/etc/function-definitions.json +++ b/library/compiler-builtins/libm/etc/function-definitions.json @@ -654,6 +654,7 @@ "src/libm_helper.rs", "src/math/arch/aarch64.rs", "src/math/arch/wasm32.rs", + "src/math/generic/rint.rs", "src/math/rint.rs" ], "type": "f64" @@ -662,6 +663,7 @@ "sources": [ "src/math/arch/aarch64.rs", "src/math/arch/wasm32.rs", + "src/math/generic/rint.rs", "src/math/rintf.rs" ], "type": "f32" diff --git a/library/compiler-builtins/libm/src/math/generic/mod.rs b/library/compiler-builtins/libm/src/math/generic/mod.rs index b08a77d5d649..d3df650e1a5b 100644 --- a/library/compiler-builtins/libm/src/math/generic/mod.rs +++ b/library/compiler-builtins/libm/src/math/generic/mod.rs @@ -3,6 +3,7 @@ mod copysign; mod fabs; mod fdim; mod floor; +mod rint; mod sqrt; mod trunc; @@ -11,5 +12,6 @@ pub use copysign::copysign; pub use fabs::fabs; pub use fdim::fdim; pub use floor::floor; +pub use rint::rint; pub use sqrt::sqrt; pub use trunc::trunc; diff --git a/library/compiler-builtins/libm/src/math/generic/rint.rs b/library/compiler-builtins/libm/src/math/generic/rint.rs new file mode 100644 index 000000000000..80ba1faac311 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/generic/rint.rs @@ -0,0 +1,72 @@ +/* SPDX-License-Identifier: MIT */ +/* origin: musl src/math/rint.c */ + +use super::super::Float; + +pub fn rint(x: F) -> F { + let toint = F::ONE / F::EPSILON; + let e = x.exp(); + let positive = x.is_sign_positive(); + + // On i386 `force_eval!` must be used to force rounding via storage to memory. Otherwise, + // the excess precission from x87 would cause an incorrect final result. + let use_force = cfg!(x86_no_sse) && F::BITS == 32 || F::BITS == 64; + + if e >= F::EXP_BIAS + F::SIG_BITS { + // No fractional part; exact result can be returned. + x + } else { + // Apply a net-zero adjustment that nudges `y` in the direction of the rounding mode. + let y = if positive { + let tmp = if use_force { force_eval!(x) } else { x } + toint; + (if use_force { force_eval!(tmp) } else { tmp } - toint) + } else { + let tmp = if use_force { force_eval!(x) } else { x } - toint; + (if use_force { force_eval!(tmp) } else { tmp } + toint) + }; + + if y == F::ZERO { + // A zero result takes the sign of the input. + if positive { F::ZERO } else { F::NEG_ZERO } + } else { + y + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn zeroes_f32() { + assert_biteq!(rint(0.0_f32), 0.0_f32); + assert_biteq!(rint(-0.0_f32), -0.0_f32); + } + + #[test] + fn sanity_check_f32() { + assert_biteq!(rint(-1.0_f32), -1.0); + assert_biteq!(rint(2.8_f32), 3.0); + assert_biteq!(rint(-0.5_f32), -0.0); + assert_biteq!(rint(0.5_f32), 0.0); + assert_biteq!(rint(-1.5_f32), -2.0); + assert_biteq!(rint(1.5_f32), 2.0); + } + + #[test] + fn zeroes_f64() { + assert_biteq!(rint(0.0_f64), 0.0_f64); + assert_biteq!(rint(-0.0_f64), -0.0_f64); + } + + #[test] + fn sanity_check_f64() { + assert_biteq!(rint(-1.0_f64), -1.0); + assert_biteq!(rint(2.8_f64), 3.0); + assert_biteq!(rint(-0.5_f64), -0.0); + assert_biteq!(rint(0.5_f64), 0.0); + assert_biteq!(rint(-1.5_f64), -2.0); + assert_biteq!(rint(1.5_f64), 2.0); + } +} diff --git a/library/compiler-builtins/libm/src/math/rint.rs b/library/compiler-builtins/libm/src/math/rint.rs index c9ea6402ec73..592583aa5e54 100644 --- a/library/compiler-builtins/libm/src/math/rint.rs +++ b/library/compiler-builtins/libm/src/math/rint.rs @@ -9,51 +9,5 @@ pub fn rint(x: f64) -> f64 { args: x, } - let one_over_e = 1.0 / f64::EPSILON; - let as_u64: u64 = x.to_bits(); - let exponent: u64 = (as_u64 >> 52) & 0x7ff; - let is_positive = (as_u64 >> 63) == 0; - if exponent >= 0x3ff + 52 { - x - } else { - let ans = if is_positive { - #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] - let x = force_eval!(x); - let xplusoneovere = x + one_over_e; - #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] - let xplusoneovere = force_eval!(xplusoneovere); - xplusoneovere - one_over_e - } else { - #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] - let x = force_eval!(x); - let xminusoneovere = x - one_over_e; - #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] - let xminusoneovere = force_eval!(xminusoneovere); - xminusoneovere + one_over_e - }; - - if ans == 0.0 { if is_positive { 0.0 } else { -0.0 } } else { ans } - } -} - -// PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520 -#[cfg(not(target_arch = "powerpc64"))] -#[cfg(test)] -mod tests { - use super::rint; - - #[test] - fn negative_zero() { - assert_eq!(rint(-0.0_f64).to_bits(), (-0.0_f64).to_bits()); - } - - #[test] - fn sanity_check() { - assert_eq!(rint(-1.0), -1.0); - assert_eq!(rint(2.8), 3.0); - assert_eq!(rint(-0.5), -0.0); - assert_eq!(rint(0.5), 0.0); - assert_eq!(rint(-1.5), -2.0); - assert_eq!(rint(1.5), 2.0); - } + super::generic::rint(x) } diff --git a/library/compiler-builtins/libm/src/math/rintf.rs b/library/compiler-builtins/libm/src/math/rintf.rs index 33b5b3ddebf6..56666df11542 100644 --- a/library/compiler-builtins/libm/src/math/rintf.rs +++ b/library/compiler-builtins/libm/src/math/rintf.rs @@ -9,51 +9,5 @@ pub fn rintf(x: f32) -> f32 { args: x, } - let one_over_e = 1.0 / f32::EPSILON; - let as_u32: u32 = x.to_bits(); - let exponent: u32 = (as_u32 >> 23) & 0xff; - let is_positive = (as_u32 >> 31) == 0; - if exponent >= 0x7f + 23 { - x - } else { - let ans = if is_positive { - #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] - let x = force_eval!(x); - let xplusoneovere = x + one_over_e; - #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] - let xplusoneovere = force_eval!(xplusoneovere); - xplusoneovere - one_over_e - } else { - #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] - let x = force_eval!(x); - let xminusoneovere = x - one_over_e; - #[cfg(all(target_arch = "x86", not(target_feature = "sse2")))] - let xminusoneovere = force_eval!(xminusoneovere); - xminusoneovere + one_over_e - }; - - if ans == 0.0 { if is_positive { 0.0 } else { -0.0 } } else { ans } - } -} - -// PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520 -#[cfg(not(target_arch = "powerpc64"))] -#[cfg(test)] -mod tests { - use super::rintf; - - #[test] - fn negative_zero() { - assert_eq!(rintf(-0.0_f32).to_bits(), (-0.0_f32).to_bits()); - } - - #[test] - fn sanity_check() { - assert_eq!(rintf(-1.0), -1.0); - assert_eq!(rintf(2.8), 3.0); - assert_eq!(rintf(-0.5), -0.0); - assert_eq!(rintf(0.5), 0.0); - assert_eq!(rintf(-1.5), -2.0); - assert_eq!(rintf(1.5), 2.0); - } + super::generic::rint(x) } From b22398d6580d1f90e020404e427b06403d204c9f Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 22 Jan 2025 10:58:29 +0000 Subject: [PATCH 2/2] Add `rintf16` and `rintf128` Use the generic algorithms to provide implementations for these routines. --- .../crates/compiler-builtins-smoke-test/src/lib.rs | 2 ++ .../libm/crates/libm-macros/src/shared.rs | 4 ++-- .../libm/crates/libm-test/benches/icount.rs | 2 ++ .../libm/crates/libm-test/benches/random.rs | 2 ++ .../libm/crates/libm-test/src/mpfloat.rs | 8 ++++++-- .../crates/libm-test/tests/compare_built_musl.rs | 6 ++++-- .../compiler-builtins/libm/crates/util/src/main.rs | 2 ++ .../libm/etc/function-definitions.json | 14 ++++++++++++++ .../compiler-builtins/libm/etc/function-list.txt | 2 ++ library/compiler-builtins/libm/src/math/mod.rs | 4 ++++ library/compiler-builtins/libm/src/math/rint.rs | 1 + library/compiler-builtins/libm/src/math/rintf.rs | 1 + .../compiler-builtins/libm/src/math/rintf128.rs | 5 +++++ library/compiler-builtins/libm/src/math/rintf16.rs | 5 +++++ 14 files changed, 52 insertions(+), 6 deletions(-) create mode 100644 library/compiler-builtins/libm/src/math/rintf128.rs create mode 100644 library/compiler-builtins/libm/src/math/rintf16.rs diff --git a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/lib.rs b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/lib.rs index 1a7aa983ee44..ccd0642a20e3 100644 --- a/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/lib.rs +++ b/library/compiler-builtins/libm/crates/compiler-builtins-smoke-test/src/lib.rs @@ -145,6 +145,8 @@ no_mangle! { remquof(x: f32, y: f32 | q: &mut c_int) -> f32; rint(x: f64) -> f64; rintf(x: f32) -> f32; + rintf128(x: f128) -> f128; + rintf16(x: f16) -> f16; round(x: f64) -> f64; roundf(x: f32) -> f32; scalbn(x: f64, y: c_int) -> f64; diff --git a/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs b/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs index 64623658d655..80bd3e90753b 100644 --- a/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs +++ b/library/compiler-builtins/libm/crates/libm-macros/src/shared.rs @@ -9,7 +9,7 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option, &[&str])] FloatTy::F16, Signature { args: &[Ty::F16], returns: &[Ty::F16] }, None, - &["ceilf16", "fabsf16", "floorf16", "sqrtf16", "truncf16"], + &["ceilf16", "fabsf16", "floorf16", "rintf16", "sqrtf16", "truncf16"], ), ( // `fn(f32) -> f32` @@ -40,7 +40,7 @@ const ALL_OPERATIONS_NESTED: &[(FloatTy, Signature, Option, &[&str])] FloatTy::F128, Signature { args: &[Ty::F128], returns: &[Ty::F128] }, None, - &["ceilf128", "fabsf128", "floorf128", "sqrtf128", "truncf128"], + &["ceilf128", "fabsf128", "floorf128", "rintf128", "sqrtf128", "truncf128"], ), ( // `(f16, f16) -> f16` diff --git a/library/compiler-builtins/libm/crates/libm-test/benches/icount.rs b/library/compiler-builtins/libm/crates/libm-test/benches/icount.rs index eae63619c579..84f953262679 100644 --- a/library/compiler-builtins/libm/crates/libm-test/benches/icount.rs +++ b/library/compiler-builtins/libm/crates/libm-test/benches/icount.rs @@ -149,6 +149,8 @@ main!( icount_bench_remquo_group, icount_bench_remquof_group, icount_bench_rint_group, + icount_bench_rintf128_group, + icount_bench_rintf16_group, icount_bench_rintf_group, icount_bench_round_group, icount_bench_roundf_group, diff --git a/library/compiler-builtins/libm/crates/libm-test/benches/random.rs b/library/compiler-builtins/libm/crates/libm-test/benches/random.rs index bd7b3597196c..4d050e817e23 100644 --- a/library/compiler-builtins/libm/crates/libm-test/benches/random.rs +++ b/library/compiler-builtins/libm/crates/libm-test/benches/random.rs @@ -127,6 +127,8 @@ libm_macros::for_each_function! { | fdimf16 | floorf128 | floorf16 + | rintf128 + | rintf16 | sqrtf128 | sqrtf16 | truncf128 diff --git a/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs b/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs index 53fade7d0ef6..a404f227b262 100644 --- a/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs +++ b/library/compiler-builtins/libm/crates/libm-test/src/mpfloat.rs @@ -170,6 +170,8 @@ libm_macros::for_each_function! { remquof, rint, rintf, + rintf128, + rintf16, round, roundf, scalbn, @@ -240,17 +242,19 @@ impl_no_round! { #[cfg(f16_enabled)] impl_no_round! { - fabsf16 => abs_mut; ceilf16 => ceil_mut; + fabsf16 => abs_mut; floorf16 => floor_mut; + rintf16 => round_even_mut; // FIXME: respect rounding mode truncf16 => trunc_mut; } #[cfg(f128_enabled)] impl_no_round! { - fabsf128 => abs_mut; ceilf128 => ceil_mut; + fabsf128 => abs_mut; floorf128 => floor_mut; + rintf128 => round_even_mut; // FIXME: respect rounding mode truncf128 => trunc_mut; } diff --git a/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs b/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs index 335496fce36c..f009816c97f1 100644 --- a/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs +++ b/library/compiler-builtins/libm/crates/libm-test/tests/compare_built_musl.rs @@ -89,9 +89,11 @@ libm_macros::for_each_function! { fdimf16, floorf128, floorf16, + rintf128, + rintf16, + sqrtf128, + sqrtf16, truncf128, truncf16, - sqrtf16, - sqrtf128, ], } diff --git a/library/compiler-builtins/libm/crates/util/src/main.rs b/library/compiler-builtins/libm/crates/util/src/main.rs index 988c01d07607..41d995b3b395 100644 --- a/library/compiler-builtins/libm/crates/util/src/main.rs +++ b/library/compiler-builtins/libm/crates/util/src/main.rs @@ -94,6 +94,8 @@ fn do_eval(basis: &str, op: &str, inputs: &[&str]) { | fdimf16 | floorf128 | floorf16 + | rintf128 + | rintf16 | sqrtf128 | sqrtf16 | truncf128 diff --git a/library/compiler-builtins/libm/etc/function-definitions.json b/library/compiler-builtins/libm/etc/function-definitions.json index 86b0882927cc..d3810b940cb0 100644 --- a/library/compiler-builtins/libm/etc/function-definitions.json +++ b/library/compiler-builtins/libm/etc/function-definitions.json @@ -668,6 +668,20 @@ ], "type": "f32" }, + "rintf128": { + "sources": [ + "src/math/generic/rint.rs", + "src/math/rintf128.rs" + ], + "type": "f128" + }, + "rintf16": { + "sources": [ + "src/math/generic/rint.rs", + "src/math/rintf16.rs" + ], + "type": "f16" + }, "round": { "sources": [ "src/libm_helper.rs", diff --git a/library/compiler-builtins/libm/etc/function-list.txt b/library/compiler-builtins/libm/etc/function-list.txt index 3bb895f4a297..41bb4e06be8d 100644 --- a/library/compiler-builtins/libm/etc/function-list.txt +++ b/library/compiler-builtins/libm/etc/function-list.txt @@ -97,6 +97,8 @@ remquo remquof rint rintf +rintf128 +rintf16 round roundf scalbn diff --git a/library/compiler-builtins/libm/src/math/mod.rs b/library/compiler-builtins/libm/src/math/mod.rs index 68d201524b4b..53d06974ceec 100644 --- a/library/compiler-builtins/libm/src/math/mod.rs +++ b/library/compiler-builtins/libm/src/math/mod.rs @@ -346,6 +346,7 @@ cfg_if! { mod fabsf16; mod fdimf16; mod floorf16; + mod rintf16; mod sqrtf16; mod truncf16; @@ -354,6 +355,7 @@ cfg_if! { pub use self::fabsf16::fabsf16; pub use self::fdimf16::fdimf16; pub use self::floorf16::floorf16; + pub use self::rintf16::rintf16; pub use self::sqrtf16::sqrtf16; pub use self::truncf16::truncf16; } @@ -366,6 +368,7 @@ cfg_if! { mod fabsf128; mod fdimf128; mod floorf128; + mod rintf128; mod sqrtf128; mod truncf128; @@ -374,6 +377,7 @@ cfg_if! { pub use self::fabsf128::fabsf128; pub use self::fdimf128::fdimf128; pub use self::floorf128::floorf128; + pub use self::rintf128::rintf128; pub use self::sqrtf128::sqrtf128; pub use self::truncf128::truncf128; } diff --git a/library/compiler-builtins/libm/src/math/rint.rs b/library/compiler-builtins/libm/src/math/rint.rs index 592583aa5e54..f409ec2821d8 100644 --- a/library/compiler-builtins/libm/src/math/rint.rs +++ b/library/compiler-builtins/libm/src/math/rint.rs @@ -1,3 +1,4 @@ +/// Round `x` to the nearest integer, breaking ties toward even. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn rint(x: f64) -> f64 { select_implementation! { diff --git a/library/compiler-builtins/libm/src/math/rintf.rs b/library/compiler-builtins/libm/src/math/rintf.rs index 56666df11542..5e9f5f718769 100644 --- a/library/compiler-builtins/libm/src/math/rintf.rs +++ b/library/compiler-builtins/libm/src/math/rintf.rs @@ -1,3 +1,4 @@ +/// Round `x` to the nearest integer, breaking ties toward even. #[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] pub fn rintf(x: f32) -> f32 { select_implementation! { diff --git a/library/compiler-builtins/libm/src/math/rintf128.rs b/library/compiler-builtins/libm/src/math/rintf128.rs new file mode 100644 index 000000000000..6b16fcd841a6 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/rintf128.rs @@ -0,0 +1,5 @@ +/// Round `x` to the nearest integer, breaking ties toward even. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn rintf128(x: f128) -> f128 { + super::generic::rint(x) +} diff --git a/library/compiler-builtins/libm/src/math/rintf16.rs b/library/compiler-builtins/libm/src/math/rintf16.rs new file mode 100644 index 000000000000..84d792561f74 --- /dev/null +++ b/library/compiler-builtins/libm/src/math/rintf16.rs @@ -0,0 +1,5 @@ +/// Round `x` to the nearest integer, breaking ties toward even. +#[cfg_attr(all(test, assert_no_panic), no_panic::no_panic)] +pub fn rintf16(x: f16) -> f16 { + super::generic::rint(x) +}