Skip to content

Commit 0f98c0e

Browse files
committed
add NaN-nondet to libm functions
1 parent 86198a1 commit 0f98c0e

File tree

2 files changed

+101
-47
lines changed

2 files changed

+101
-47
lines changed

src/tools/miri/src/shims/foreign_items.rs

Lines changed: 61 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ use rustc_target::{
2323

2424
use super::backtrace::EvalContextExt as _;
2525
use crate::*;
26+
use helpers::{ToHost, ToSoft};
2627

2728
/// Type of dynamic symbols (for `dlsym` et al)
2829
#[derive(Debug, Copy, Clone)]
@@ -886,23 +887,26 @@ trait EvalContextExtPriv<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
886887
| "tgammaf"
887888
=> {
888889
let [f] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
890+
let f = this.read_scalar(f)?.to_f32()?;
889891
// FIXME: Using host floats.
890-
let f = f32::from_bits(this.read_scalar(f)?.to_u32()?);
892+
let f_host = f.to_host();
891893
let res = match link_name.as_str() {
892-
"cbrtf" => f.cbrt(),
893-
"coshf" => f.cosh(),
894-
"sinhf" => f.sinh(),
895-
"tanf" => f.tan(),
896-
"tanhf" => f.tanh(),
897-
"acosf" => f.acos(),
898-
"asinf" => f.asin(),
899-
"atanf" => f.atan(),
900-
"log1pf" => f.ln_1p(),
901-
"expm1f" => f.exp_m1(),
902-
"tgammaf" => f.gamma(),
894+
"cbrtf" => f_host.cbrt(),
895+
"coshf" => f_host.cosh(),
896+
"sinhf" => f_host.sinh(),
897+
"tanf" => f_host.tan(),
898+
"tanhf" => f_host.tanh(),
899+
"acosf" => f_host.acos(),
900+
"asinf" => f_host.asin(),
901+
"atanf" => f_host.atan(),
902+
"log1pf" => f_host.ln_1p(),
903+
"expm1f" => f_host.exp_m1(),
904+
"tgammaf" => f_host.gamma(),
903905
_ => bug!(),
904906
};
905-
this.write_scalar(Scalar::from_u32(res.to_bits()), dest)?;
907+
let res = res.to_soft();
908+
let res = this.adjust_nan(res, &[f]);
909+
this.write_scalar(res, dest)?;
906910
}
907911
#[rustfmt::skip]
908912
| "_hypotf"
@@ -911,19 +915,20 @@ trait EvalContextExtPriv<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
911915
| "fdimf"
912916
=> {
913917
let [f1, f2] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
918+
let f1 = this.read_scalar(f1)?.to_f32()?;
919+
let f2 = this.read_scalar(f2)?.to_f32()?;
914920
// underscore case for windows, here and below
915921
// (see https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/floating-point-primitives?view=vs-2019)
916922
// FIXME: Using host floats.
917-
let f1 = f32::from_bits(this.read_scalar(f1)?.to_u32()?);
918-
let f2 = f32::from_bits(this.read_scalar(f2)?.to_u32()?);
919923
let res = match link_name.as_str() {
920-
"_hypotf" | "hypotf" => f1.hypot(f2),
921-
"atan2f" => f1.atan2(f2),
924+
"_hypotf" | "hypotf" => f1.to_host().hypot(f2.to_host()).to_soft(),
925+
"atan2f" => f1.to_host().atan2(f2.to_host()).to_soft(),
922926
#[allow(deprecated)]
923-
"fdimf" => f1.abs_sub(f2),
927+
"fdimf" => f1.to_host().abs_sub(f2.to_host()).to_soft(),
924928
_ => bug!(),
925929
};
926-
this.write_scalar(Scalar::from_u32(res.to_bits()), dest)?;
930+
let res = this.adjust_nan(res, &[f1, f2]);
931+
this.write_scalar(res, dest)?;
927932
}
928933
#[rustfmt::skip]
929934
| "cbrt"
@@ -939,23 +944,26 @@ trait EvalContextExtPriv<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
939944
| "tgamma"
940945
=> {
941946
let [f] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
947+
let f = this.read_scalar(f)?.to_f64()?;
942948
// FIXME: Using host floats.
943-
let f = f64::from_bits(this.read_scalar(f)?.to_u64()?);
949+
let f_host = f.to_host();
944950
let res = match link_name.as_str() {
945-
"cbrt" => f.cbrt(),
946-
"cosh" => f.cosh(),
947-
"sinh" => f.sinh(),
948-
"tan" => f.tan(),
949-
"tanh" => f.tanh(),
950-
"acos" => f.acos(),
951-
"asin" => f.asin(),
952-
"atan" => f.atan(),
953-
"log1p" => f.ln_1p(),
954-
"expm1" => f.exp_m1(),
955-
"tgamma" => f.gamma(),
951+
"cbrt" => f_host.cbrt(),
952+
"cosh" => f_host.cosh(),
953+
"sinh" => f_host.sinh(),
954+
"tan" => f_host.tan(),
955+
"tanh" => f_host.tanh(),
956+
"acos" => f_host.acos(),
957+
"asin" => f_host.asin(),
958+
"atan" => f_host.atan(),
959+
"log1p" => f_host.ln_1p(),
960+
"expm1" => f_host.exp_m1(),
961+
"tgamma" => f_host.gamma(),
956962
_ => bug!(),
957963
};
958-
this.write_scalar(Scalar::from_u64(res.to_bits()), dest)?;
964+
let res = res.to_soft();
965+
let res = this.adjust_nan(res, &[f]);
966+
this.write_scalar(res, dest)?;
959967
}
960968
#[rustfmt::skip]
961969
| "_hypot"
@@ -964,17 +972,20 @@ trait EvalContextExtPriv<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
964972
| "fdim"
965973
=> {
966974
let [f1, f2] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
975+
let f1 = this.read_scalar(f1)?.to_f64()?;
976+
let f2 = this.read_scalar(f2)?.to_f64()?;
977+
// underscore case for windows, here and below
978+
// (see https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/floating-point-primitives?view=vs-2019)
967979
// FIXME: Using host floats.
968-
let f1 = f64::from_bits(this.read_scalar(f1)?.to_u64()?);
969-
let f2 = f64::from_bits(this.read_scalar(f2)?.to_u64()?);
970980
let res = match link_name.as_str() {
971-
"_hypot" | "hypot" => f1.hypot(f2),
972-
"atan2" => f1.atan2(f2),
981+
"_hypot" | "hypot" => f1.to_host().hypot(f2.to_host()).to_soft(),
982+
"atan2" => f1.to_host().atan2(f2.to_host()).to_soft(),
973983
#[allow(deprecated)]
974-
"fdim" => f1.abs_sub(f2),
984+
"fdim" => f1.to_host().abs_sub(f2.to_host()).to_soft(),
975985
_ => bug!(),
976986
};
977-
this.write_scalar(Scalar::from_u64(res.to_bits()), dest)?;
987+
let res = this.adjust_nan(res, &[f1, f2]);
988+
this.write_scalar(res, dest)?;
978989
}
979990
#[rustfmt::skip]
980991
| "_ldexp"
@@ -987,27 +998,30 @@ trait EvalContextExtPriv<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
987998
let exp = this.read_scalar(exp)?.to_i32()?;
988999

9891000
let res = x.scalbn(exp);
990-
this.write_scalar(Scalar::from_f64(res), dest)?;
1001+
let res = this.adjust_nan(res, &[x]);
1002+
this.write_scalar(res, dest)?;
9911003
}
9921004
"lgammaf_r" => {
9931005
let [x, signp] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
994-
// FIXME: Using host floats.
995-
let x = f32::from_bits(this.read_scalar(x)?.to_u32()?);
1006+
let x = this.read_scalar(x)?.to_f32()?;
9961007
let signp = this.deref_pointer(signp)?;
9971008

998-
let (res, sign) = x.ln_gamma();
1009+
// FIXME: Using host floats.
1010+
let (res, sign) = x.to_host().ln_gamma();
9991011
this.write_int(sign, &signp)?;
1000-
this.write_scalar(Scalar::from_u32(res.to_bits()), dest)?;
1012+
let res = this.adjust_nan(res.to_soft(), &[x]);
1013+
this.write_scalar(res, dest)?;
10011014
}
10021015
"lgamma_r" => {
10031016
let [x, signp] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
1004-
// FIXME: Using host floats.
1005-
let x = f64::from_bits(this.read_scalar(x)?.to_u64()?);
1017+
let x = this.read_scalar(x)?.to_f64()?;
10061018
let signp = this.deref_pointer(signp)?;
10071019

1008-
let (res, sign) = x.ln_gamma();
1020+
// FIXME: Using host floats.
1021+
let (res, sign) = x.to_host().ln_gamma();
10091022
this.write_int(sign, &signp)?;
1010-
this.write_scalar(Scalar::from_u64(res.to_bits()), dest)?;
1023+
let res = this.adjust_nan(res.to_soft(), &[x]);
1024+
this.write_scalar(res, dest)?;
10111025
}
10121026

10131027
// LLVM intrinsics

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

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,16 @@
1+
#![feature(float_gamma)]
12
use std::collections::HashSet;
23
use std::fmt;
34
use std::hash::Hash;
45
use std::hint::black_box;
56

7+
fn ldexp(a: f64, b: i32) -> f64 {
8+
extern "C" {
9+
fn ldexp(x: f64, n: i32) -> f64;
10+
}
11+
unsafe { ldexp(a, b) }
12+
}
13+
614
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
715
enum Sign {
816
Neg = 1,
@@ -298,6 +306,20 @@ fn test_f32() {
298306
HashSet::from_iter([F32::nan(Pos, Quiet, 0), F32::nan(Neg, Quiet, 0)]),
299307
|| F32::from(nan.powi(1)),
300308
);
309+
310+
// libm functions
311+
check_all_outcomes(
312+
HashSet::from_iter([F32::nan(Pos, Quiet, 0), F32::nan(Neg, Quiet, 0)]),
313+
|| F32::from(nan.sinh()),
314+
);
315+
check_all_outcomes(
316+
HashSet::from_iter([F32::nan(Pos, Quiet, 0), F32::nan(Neg, Quiet, 0)]),
317+
|| F32::from(nan.atan2(nan)),
318+
);
319+
check_all_outcomes(
320+
HashSet::from_iter([F32::nan(Pos, Quiet, 0), F32::nan(Neg, Quiet, 0)]),
321+
|| F32::from(nan.ln_gamma().0),
322+
);
301323
}
302324

303325
fn test_f64() {
@@ -407,6 +429,24 @@ fn test_f64() {
407429
HashSet::from_iter([F64::nan(Pos, Quiet, 0), F64::nan(Neg, Quiet, 0)]),
408430
|| F64::from(nan.powi(1)),
409431
);
432+
433+
// libm functions
434+
check_all_outcomes(
435+
HashSet::from_iter([F64::nan(Pos, Quiet, 0), F64::nan(Neg, Quiet, 0)]),
436+
|| F64::from(nan.sinh()),
437+
);
438+
check_all_outcomes(
439+
HashSet::from_iter([F64::nan(Pos, Quiet, 0), F64::nan(Neg, Quiet, 0)]),
440+
|| F64::from(nan.atan2(nan)),
441+
);
442+
check_all_outcomes(
443+
HashSet::from_iter([F64::nan(Pos, Quiet, 0), F64::nan(Neg, Quiet, 0)]),
444+
|| F64::from(ldexp(nan, 1)),
445+
);
446+
check_all_outcomes(
447+
HashSet::from_iter([F64::nan(Pos, Quiet, 0), F64::nan(Neg, Quiet, 0)]),
448+
|| F64::from(nan.ln_gamma().0),
449+
);
410450
}
411451

412452
fn test_casts() {

0 commit comments

Comments
 (0)