implement the rounding intrinsics using apfloat rounding

This commit is contained in:
Ralf Jung 2024-01-06 12:02:08 +01:00
parent 39c714b49b
commit 1c98b78eb7
3 changed files with 47 additions and 23 deletions

View file

@ -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();

View file

@ -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()),

View file

@ -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);