diff options
| -rw-r--r-- | src/tools/miri/src/shims/foreign_items.rs | 108 | ||||
| -rw-r--r-- | src/tools/miri/tests/pass/float_nan.rs | 40 |
2 files changed, 101 insertions, 47 deletions
diff --git a/src/tools/miri/src/shims/foreign_items.rs b/src/tools/miri/src/shims/foreign_items.rs index 8ddfc05dd30..e7b2a6823ed 100644 --- a/src/tools/miri/src/shims/foreign_items.rs +++ b/src/tools/miri/src/shims/foreign_items.rs @@ -23,6 +23,7 @@ use rustc_target::{ use super::backtrace::EvalContextExt as _; use crate::*; +use helpers::{ToHost, ToSoft}; /// Type of dynamic symbols (for `dlsym` et al) #[derive(Debug, Copy, Clone)] @@ -886,23 +887,26 @@ trait EvalContextExtPriv<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { | "tgammaf" => { let [f] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let f = this.read_scalar(f)?.to_f32()?; // FIXME: Using host floats. - let f = f32::from_bits(this.read_scalar(f)?.to_u32()?); + let f_host = f.to_host(); let res = match link_name.as_str() { - "cbrtf" => f.cbrt(), - "coshf" => f.cosh(), - "sinhf" => f.sinh(), - "tanf" => f.tan(), - "tanhf" => f.tanh(), - "acosf" => f.acos(), - "asinf" => f.asin(), - "atanf" => f.atan(), - "log1pf" => f.ln_1p(), - "expm1f" => f.exp_m1(), - "tgammaf" => f.gamma(), + "cbrtf" => f_host.cbrt(), + "coshf" => f_host.cosh(), + "sinhf" => f_host.sinh(), + "tanf" => f_host.tan(), + "tanhf" => f_host.tanh(), + "acosf" => f_host.acos(), + "asinf" => f_host.asin(), + "atanf" => f_host.atan(), + "log1pf" => f_host.ln_1p(), + "expm1f" => f_host.exp_m1(), + "tgammaf" => f_host.gamma(), _ => bug!(), }; - this.write_scalar(Scalar::from_u32(res.to_bits()), dest)?; + let res = res.to_soft(); + let res = this.adjust_nan(res, &[f]); + this.write_scalar(res, dest)?; } #[rustfmt::skip] | "_hypotf" @@ -911,19 +915,20 @@ trait EvalContextExtPriv<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { | "fdimf" => { let [f1, f2] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let f1 = this.read_scalar(f1)?.to_f32()?; + let f2 = this.read_scalar(f2)?.to_f32()?; // underscore case for windows, here and below // (see https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/floating-point-primitives?view=vs-2019) // FIXME: Using host floats. - let f1 = f32::from_bits(this.read_scalar(f1)?.to_u32()?); - let f2 = f32::from_bits(this.read_scalar(f2)?.to_u32()?); let res = match link_name.as_str() { - "_hypotf" | "hypotf" => f1.hypot(f2), - "atan2f" => f1.atan2(f2), + "_hypotf" | "hypotf" => f1.to_host().hypot(f2.to_host()).to_soft(), + "atan2f" => f1.to_host().atan2(f2.to_host()).to_soft(), #[allow(deprecated)] - "fdimf" => f1.abs_sub(f2), + "fdimf" => f1.to_host().abs_sub(f2.to_host()).to_soft(), _ => bug!(), }; - this.write_scalar(Scalar::from_u32(res.to_bits()), dest)?; + let res = this.adjust_nan(res, &[f1, f2]); + this.write_scalar(res, dest)?; } #[rustfmt::skip] | "cbrt" @@ -939,23 +944,26 @@ trait EvalContextExtPriv<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { | "tgamma" => { let [f] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let f = this.read_scalar(f)?.to_f64()?; // FIXME: Using host floats. - let f = f64::from_bits(this.read_scalar(f)?.to_u64()?); + let f_host = f.to_host(); let res = match link_name.as_str() { - "cbrt" => f.cbrt(), - "cosh" => f.cosh(), - "sinh" => f.sinh(), - "tan" => f.tan(), - "tanh" => f.tanh(), - "acos" => f.acos(), - "asin" => f.asin(), - "atan" => f.atan(), - "log1p" => f.ln_1p(), - "expm1" => f.exp_m1(), - "tgamma" => f.gamma(), + "cbrt" => f_host.cbrt(), + "cosh" => f_host.cosh(), + "sinh" => f_host.sinh(), + "tan" => f_host.tan(), + "tanh" => f_host.tanh(), + "acos" => f_host.acos(), + "asin" => f_host.asin(), + "atan" => f_host.atan(), + "log1p" => f_host.ln_1p(), + "expm1" => f_host.exp_m1(), + "tgamma" => f_host.gamma(), _ => bug!(), }; - this.write_scalar(Scalar::from_u64(res.to_bits()), dest)?; + let res = res.to_soft(); + let res = this.adjust_nan(res, &[f]); + this.write_scalar(res, dest)?; } #[rustfmt::skip] | "_hypot" @@ -964,17 +972,20 @@ trait EvalContextExtPriv<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { | "fdim" => { let [f1, f2] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let f1 = this.read_scalar(f1)?.to_f64()?; + let f2 = this.read_scalar(f2)?.to_f64()?; + // underscore case for windows, here and below + // (see https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/floating-point-primitives?view=vs-2019) // FIXME: Using host floats. - let f1 = f64::from_bits(this.read_scalar(f1)?.to_u64()?); - let f2 = f64::from_bits(this.read_scalar(f2)?.to_u64()?); let res = match link_name.as_str() { - "_hypot" | "hypot" => f1.hypot(f2), - "atan2" => f1.atan2(f2), + "_hypot" | "hypot" => f1.to_host().hypot(f2.to_host()).to_soft(), + "atan2" => f1.to_host().atan2(f2.to_host()).to_soft(), #[allow(deprecated)] - "fdim" => f1.abs_sub(f2), + "fdim" => f1.to_host().abs_sub(f2.to_host()).to_soft(), _ => bug!(), }; - this.write_scalar(Scalar::from_u64(res.to_bits()), dest)?; + let res = this.adjust_nan(res, &[f1, f2]); + this.write_scalar(res, dest)?; } #[rustfmt::skip] | "_ldexp" @@ -987,27 +998,30 @@ trait EvalContextExtPriv<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { let exp = this.read_scalar(exp)?.to_i32()?; let res = x.scalbn(exp); - this.write_scalar(Scalar::from_f64(res), dest)?; + let res = this.adjust_nan(res, &[x]); + this.write_scalar(res, dest)?; } "lgammaf_r" => { let [x, signp] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; - // FIXME: Using host floats. - let x = f32::from_bits(this.read_scalar(x)?.to_u32()?); + let x = this.read_scalar(x)?.to_f32()?; let signp = this.deref_pointer(signp)?; - let (res, sign) = x.ln_gamma(); + // FIXME: Using host floats. + let (res, sign) = x.to_host().ln_gamma(); this.write_int(sign, &signp)?; - this.write_scalar(Scalar::from_u32(res.to_bits()), dest)?; + let res = this.adjust_nan(res.to_soft(), &[x]); + this.write_scalar(res, dest)?; } "lgamma_r" => { let [x, signp] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; - // FIXME: Using host floats. - let x = f64::from_bits(this.read_scalar(x)?.to_u64()?); + let x = this.read_scalar(x)?.to_f64()?; let signp = this.deref_pointer(signp)?; - let (res, sign) = x.ln_gamma(); + // FIXME: Using host floats. + let (res, sign) = x.to_host().ln_gamma(); this.write_int(sign, &signp)?; - this.write_scalar(Scalar::from_u64(res.to_bits()), dest)?; + let res = this.adjust_nan(res.to_soft(), &[x]); + this.write_scalar(res, dest)?; } // LLVM intrinsics diff --git a/src/tools/miri/tests/pass/float_nan.rs b/src/tools/miri/tests/pass/float_nan.rs index 99151e5df7c..5e717bdca00 100644 --- a/src/tools/miri/tests/pass/float_nan.rs +++ b/src/tools/miri/tests/pass/float_nan.rs @@ -1,8 +1,16 @@ +#![feature(float_gamma)] use std::collections::HashSet; use std::fmt; use std::hash::Hash; use std::hint::black_box; +fn ldexp(a: f64, b: i32) -> f64 { + extern "C" { + fn ldexp(x: f64, n: i32) -> f64; + } + unsafe { ldexp(a, b) } +} + #[derive(Clone, Copy, Debug, PartialEq, Eq)] enum Sign { Neg = 1, @@ -298,6 +306,20 @@ fn test_f32() { HashSet::from_iter([F32::nan(Pos, Quiet, 0), F32::nan(Neg, Quiet, 0)]), || F32::from(nan.powi(1)), ); + + // libm functions + check_all_outcomes( + HashSet::from_iter([F32::nan(Pos, Quiet, 0), F32::nan(Neg, Quiet, 0)]), + || F32::from(nan.sinh()), + ); + check_all_outcomes( + HashSet::from_iter([F32::nan(Pos, Quiet, 0), F32::nan(Neg, Quiet, 0)]), + || F32::from(nan.atan2(nan)), + ); + check_all_outcomes( + HashSet::from_iter([F32::nan(Pos, Quiet, 0), F32::nan(Neg, Quiet, 0)]), + || F32::from(nan.ln_gamma().0), + ); } fn test_f64() { @@ -407,6 +429,24 @@ fn test_f64() { HashSet::from_iter([F64::nan(Pos, Quiet, 0), F64::nan(Neg, Quiet, 0)]), || F64::from(nan.powi(1)), ); + + // libm functions + check_all_outcomes( + HashSet::from_iter([F64::nan(Pos, Quiet, 0), F64::nan(Neg, Quiet, 0)]), + || F64::from(nan.sinh()), + ); + check_all_outcomes( + HashSet::from_iter([F64::nan(Pos, Quiet, 0), F64::nan(Neg, Quiet, 0)]), + || F64::from(nan.atan2(nan)), + ); + check_all_outcomes( + HashSet::from_iter([F64::nan(Pos, Quiet, 0), F64::nan(Neg, Quiet, 0)]), + || F64::from(ldexp(nan, 1)), + ); + check_all_outcomes( + HashSet::from_iter([F64::nan(Pos, Quiet, 0), F64::nan(Neg, Quiet, 0)]), + || F64::from(nan.ln_gamma().0), + ); } fn test_casts() { |
