diff --git a/src/tools/miri/src/shims/intrinsics/mod.rs b/src/tools/miri/src/shims/intrinsics/mod.rs index cc81ef6e6c91..a1db7bf74f28 100644 --- a/src/tools/miri/src/shims/intrinsics/mod.rs +++ b/src/tools/miri/src/shims/intrinsics/mod.rs @@ -145,17 +145,30 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { "fabsf32" => { let [f] = check_arg_count(args)?; let f = this.read_scalar(f)?.to_f32()?; - // Can be implemented in soft-floats. // This is a "bitwise" operation, so there's no NaN non-determinism. this.write_scalar(Scalar::from_f32(f.abs()), dest)?; } "fabsf64" => { let [f] = check_arg_count(args)?; let f = this.read_scalar(f)?.to_f64()?; - // Can be implemented in soft-floats. // This is a "bitwise" operation, so there's no NaN non-determinism. this.write_scalar(Scalar::from_f64(f.abs()), dest)?; } + "floorf32" | "ceilf32" | "truncf32" | "roundf32" | "rintf32" => { + let [f] = check_arg_count(args)?; + let f = this.read_scalar(f)?.to_f32()?; + let mode = match intrinsic_name { + "floorf32" => Round::TowardNegative, + "ceilf32" => Round::TowardPositive, + "truncf32" => Round::TowardZero, + "roundf32" => Round::NearestTiesToAway, + "rintf32" => Round::NearestTiesToEven, + _ => bug!(), + }; + let res = f.round_to_integral(mode).value; + let res = this.adjust_nan(res, &[f]); + this.write_scalar(res, dest)?; + } #[rustfmt::skip] | "sinf32" | "cosf32" @@ -165,11 +178,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { | "logf32" | "log10f32" | "log2f32" - | "floorf32" - | "ceilf32" - | "truncf32" - | "roundf32" - | "rintf32" => { let [f] = check_arg_count(args)?; let f = this.read_scalar(f)?.to_f32()?; @@ -184,11 +192,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { "logf32" => f_host.ln(), "log10f32" => f_host.log10(), "log2f32" => f_host.log2(), - "floorf32" => f_host.floor(), - "ceilf32" => f_host.ceil(), - "truncf32" => f_host.trunc(), - "roundf32" => f_host.round(), - "rintf32" => f_host.round_ties_even(), _ => bug!(), }; let res = res.to_soft(); @@ -196,6 +199,21 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { this.write_scalar(res, dest)?; } + "floorf64" | "ceilf64" | "truncf64" | "roundf64" | "rintf64" => { + let [f] = check_arg_count(args)?; + let f = this.read_scalar(f)?.to_f64()?; + let mode = match intrinsic_name { + "floorf64" => Round::TowardNegative, + "ceilf64" => Round::TowardPositive, + "truncf64" => Round::TowardZero, + "roundf64" => Round::NearestTiesToAway, + "rintf64" => Round::NearestTiesToEven, + _ => bug!(), + }; + let res = f.round_to_integral(mode).value; + let res = this.adjust_nan(res, &[f]); + this.write_scalar(res, dest)?; + } #[rustfmt::skip] | "sinf64" | "cosf64" @@ -205,11 +223,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { | "logf64" | "log10f64" | "log2f64" - | "floorf64" - | "ceilf64" - | "truncf64" - | "roundf64" - | "rintf64" => { let [f] = check_arg_count(args)?; let f = this.read_scalar(f)?.to_f64()?; @@ -224,11 +237,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { "logf64" => f_host.ln(), "log10f64" => f_host.log10(), "log2f64" => f_host.log2(), - "floorf64" => f_host.floor(), - "ceilf64" => f_host.ceil(), - "truncf64" => f_host.trunc(), - "roundf64" => f_host.round(), - "rintf64" => f_host.round_ties_even(), _ => bug!(), }; let res = res.to_soft(); diff --git a/src/tools/miri/tests/pass/float_nan.rs b/src/tools/miri/tests/pass/float_nan.rs index 207ce70fb20e..4bfd12245ef1 100644 --- a/src/tools/miri/tests/pass/float_nan.rs +++ b/src/tools/miri/tests/pass/float_nan.rs @@ -264,6 +264,10 @@ fn test_f32() { HashSet::from_iter([F32::nan(Pos, Quiet, 0), F32::nan(Neg, Quiet, 0)]), || F32::from(f32::min(nan, nan)), ); + check_all_outcomes( + HashSet::from_iter([F32::nan(Pos, Quiet, 0), F32::nan(Neg, Quiet, 0)]), + || F32::from(nan.floor()), + ); check_all_outcomes( HashSet::from_iter([F32::nan(Pos, Quiet, 0), F32::nan(Neg, Quiet, 0)]), || F32::from(nan.sin()), @@ -376,6 +380,10 @@ fn test_f64() { HashSet::from_iter([F64::nan(Pos, Quiet, 0), F64::nan(Neg, Quiet, 0)]), || F64::from(f64::min(nan, nan)), ); + check_all_outcomes( + HashSet::from_iter([F64::nan(Pos, Quiet, 0), F64::nan(Neg, Quiet, 0)]), + || F64::from(nan.floor()), + ); check_all_outcomes( HashSet::from_iter([F64::nan(Pos, Quiet, 0), F64::nan(Neg, Quiet, 0)]), || F64::from(nan.sin()), diff --git a/src/tools/miri/tests/pass/intrinsics-math.rs b/src/tools/miri/tests/pass/intrinsics-math.rs index 589864f4f4ba..c32ac9449d1e 100644 --- a/src/tools/miri/tests/pass/intrinsics-math.rs +++ b/src/tools/miri/tests/pass/intrinsics-math.rs @@ -1,4 +1,5 @@ #![feature(float_gamma)] +#![feature(round_ties_even)] use std::{f32, f64}; macro_rules! assert_approx_eq { @@ -73,7 +74,14 @@ pub fn main() { assert_approx_eq!(3.0f64.hypot(4.0f64), 5.0f64); assert_eq!(3.3_f32.round(), 3.0); - assert_eq!(3.3_f64.round(), 3.0); + assert_eq!(2.5_f32.round(), 3.0); + assert_eq!(3.9_f64.round(), 4.0); + assert_eq!(2.5_f64.round(), 3.0); + + assert_eq!(3.3_f32.round_ties_even(), 3.0); + assert_eq!(2.5_f32.round_ties_even(), 2.0); + assert_eq!(3.9_f64.round_ties_even(), 4.0); + assert_eq!(2.5_f64.round_ties_even(), 2.0); assert_eq!(ldexp(0.65f64, 3i32), 5.2f64); assert_eq!(ldexp(1.42, 0xFFFF), f64::INFINITY);