Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit 1c98b78

Browse files
committed
implement the rounding intrinsics using apfloat rounding
1 parent 39c714b commit 1c98b78

File tree

3 files changed

+47
-23
lines changed

3 files changed

+47
-23
lines changed

src/tools/miri/src/shims/intrinsics/mod.rs

Lines changed: 30 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -145,17 +145,30 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
145145
"fabsf32" => {
146146
let [f] = check_arg_count(args)?;
147147
let f = this.read_scalar(f)?.to_f32()?;
148-
// Can be implemented in soft-floats.
149148
// This is a "bitwise" operation, so there's no NaN non-determinism.
150149
this.write_scalar(Scalar::from_f32(f.abs()), dest)?;
151150
}
152151
"fabsf64" => {
153152
let [f] = check_arg_count(args)?;
154153
let f = this.read_scalar(f)?.to_f64()?;
155-
// Can be implemented in soft-floats.
156154
// This is a "bitwise" operation, so there's no NaN non-determinism.
157155
this.write_scalar(Scalar::from_f64(f.abs()), dest)?;
158156
}
157+
"floorf32" | "ceilf32" | "truncf32" | "roundf32" | "rintf32" => {
158+
let [f] = check_arg_count(args)?;
159+
let f = this.read_scalar(f)?.to_f32()?;
160+
let mode = match intrinsic_name {
161+
"floorf32" => Round::TowardNegative,
162+
"ceilf32" => Round::TowardPositive,
163+
"truncf32" => Round::TowardZero,
164+
"roundf32" => Round::NearestTiesToAway,
165+
"rintf32" => Round::NearestTiesToEven,
166+
_ => bug!(),
167+
};
168+
let res = f.round_to_integral(mode).value;
169+
let res = this.adjust_nan(res, &[f]);
170+
this.write_scalar(res, dest)?;
171+
}
159172
#[rustfmt::skip]
160173
| "sinf32"
161174
| "cosf32"
@@ -165,11 +178,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
165178
| "logf32"
166179
| "log10f32"
167180
| "log2f32"
168-
| "floorf32"
169-
| "ceilf32"
170-
| "truncf32"
171-
| "roundf32"
172-
| "rintf32"
173181
=> {
174182
let [f] = check_arg_count(args)?;
175183
let f = this.read_scalar(f)?.to_f32()?;
@@ -184,18 +192,28 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
184192
"logf32" => f_host.ln(),
185193
"log10f32" => f_host.log10(),
186194
"log2f32" => f_host.log2(),
187-
"floorf32" => f_host.floor(),
188-
"ceilf32" => f_host.ceil(),
189-
"truncf32" => f_host.trunc(),
190-
"roundf32" => f_host.round(),
191-
"rintf32" => f_host.round_ties_even(),
192195
_ => bug!(),
193196
};
194197
let res = res.to_soft();
195198
let res = this.adjust_nan(res, &[f]);
196199
this.write_scalar(res, dest)?;
197200
}
198201

202+
"floorf64" | "ceilf64" | "truncf64" | "roundf64" | "rintf64" => {
203+
let [f] = check_arg_count(args)?;
204+
let f = this.read_scalar(f)?.to_f64()?;
205+
let mode = match intrinsic_name {
206+
"floorf64" => Round::TowardNegative,
207+
"ceilf64" => Round::TowardPositive,
208+
"truncf64" => Round::TowardZero,
209+
"roundf64" => Round::NearestTiesToAway,
210+
"rintf64" => Round::NearestTiesToEven,
211+
_ => bug!(),
212+
};
213+
let res = f.round_to_integral(mode).value;
214+
let res = this.adjust_nan(res, &[f]);
215+
this.write_scalar(res, dest)?;
216+
}
199217
#[rustfmt::skip]
200218
| "sinf64"
201219
| "cosf64"
@@ -205,11 +223,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
205223
| "logf64"
206224
| "log10f64"
207225
| "log2f64"
208-
| "floorf64"
209-
| "ceilf64"
210-
| "truncf64"
211-
| "roundf64"
212-
| "rintf64"
213226
=> {
214227
let [f] = check_arg_count(args)?;
215228
let f = this.read_scalar(f)?.to_f64()?;
@@ -224,11 +237,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
224237
"logf64" => f_host.ln(),
225238
"log10f64" => f_host.log10(),
226239
"log2f64" => f_host.log2(),
227-
"floorf64" => f_host.floor(),
228-
"ceilf64" => f_host.ceil(),
229-
"truncf64" => f_host.trunc(),
230-
"roundf64" => f_host.round(),
231-
"rintf64" => f_host.round_ties_even(),
232240
_ => bug!(),
233241
};
234242
let res = res.to_soft();

src/tools/miri/tests/pass/float_nan.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,10 @@ fn test_f32() {
264264
HashSet::from_iter([F32::nan(Pos, Quiet, 0), F32::nan(Neg, Quiet, 0)]),
265265
|| F32::from(f32::min(nan, nan)),
266266
);
267+
check_all_outcomes(
268+
HashSet::from_iter([F32::nan(Pos, Quiet, 0), F32::nan(Neg, Quiet, 0)]),
269+
|| F32::from(nan.floor()),
270+
);
267271
check_all_outcomes(
268272
HashSet::from_iter([F32::nan(Pos, Quiet, 0), F32::nan(Neg, Quiet, 0)]),
269273
|| F32::from(nan.sin()),
@@ -376,6 +380,10 @@ fn test_f64() {
376380
HashSet::from_iter([F64::nan(Pos, Quiet, 0), F64::nan(Neg, Quiet, 0)]),
377381
|| F64::from(f64::min(nan, nan)),
378382
);
383+
check_all_outcomes(
384+
HashSet::from_iter([F64::nan(Pos, Quiet, 0), F64::nan(Neg, Quiet, 0)]),
385+
|| F64::from(nan.floor()),
386+
);
379387
check_all_outcomes(
380388
HashSet::from_iter([F64::nan(Pos, Quiet, 0), F64::nan(Neg, Quiet, 0)]),
381389
|| F64::from(nan.sin()),

src/tools/miri/tests/pass/intrinsics-math.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#![feature(float_gamma)]
2+
#![feature(round_ties_even)]
23
use std::{f32, f64};
34

45
macro_rules! assert_approx_eq {
@@ -73,7 +74,14 @@ pub fn main() {
7374
assert_approx_eq!(3.0f64.hypot(4.0f64), 5.0f64);
7475

7576
assert_eq!(3.3_f32.round(), 3.0);
76-
assert_eq!(3.3_f64.round(), 3.0);
77+
assert_eq!(2.5_f32.round(), 3.0);
78+
assert_eq!(3.9_f64.round(), 4.0);
79+
assert_eq!(2.5_f64.round(), 3.0);
80+
81+
assert_eq!(3.3_f32.round_ties_even(), 3.0);
82+
assert_eq!(2.5_f32.round_ties_even(), 2.0);
83+
assert_eq!(3.9_f64.round_ties_even(), 4.0);
84+
assert_eq!(2.5_f64.round_ties_even(), 2.0);
7785

7886
assert_eq!(ldexp(0.65f64, 3i32), 5.2f64);
7987
assert_eq!(ldexp(1.42, 0xFFFF), f64::INFINITY);

0 commit comments

Comments
 (0)