Skip to content

Commit f49980c

Browse files
apply requests from reviewer
1 parent 22f78b1 commit f49980c

File tree

2 files changed

+21
-46
lines changed

2 files changed

+21
-46
lines changed

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

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ mod simd;
66
use std::ops::Neg;
77

88
use rand::Rng;
9-
use rand::rngs::StdRng;
109
use rustc_abi::Size;
1110
use rustc_apfloat::ieee::{IeeeFloat, Semantics};
1211
use rustc_apfloat::{self, Float, Round};
@@ -18,6 +17,7 @@ use self::atomic::EvalContextExt as _;
1817
use self::helpers::{ToHost, ToSoft, check_intrinsic_arg_count};
1918
use self::simd::EvalContextExt as _;
2019
use crate::math::{IeeeExt, apply_random_float_error_ulp};
20+
use crate::operator::EvalContextExt as _;
2121
use crate::*;
2222

2323
impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {}
@@ -490,15 +490,6 @@ fn apply_random_float_error_to_imm<'tcx>(
490490
interp_ok(ImmTy::from_scalar_int(res, val.layout))
491491
}
492492

493-
/// Returns either a SNaN or a QNaN, with a randomly generated payload.
494-
fn random_nan<S: Semantics>(rng: &mut StdRng) -> IeeeFloat<S> {
495-
if rng.random() {
496-
IeeeFloat::<S>::snan(Some(rng.random()))
497-
} else {
498-
IeeeFloat::<S>::qnan(Some(rng.random()))
499-
}
500-
}
501-
502493
/// For the intrinsics:
503494
/// - sinf32, sinf64
504495
/// - cosf32, cosf64
@@ -547,15 +538,17 @@ fn fixed_float_value<S: Semantics>(
547538
// 1^y = 1 for any y, even a NaN, *but* not a SNaN
548539
("powf32" | "powf64", [base, exp]) if *base == one => {
549540
let rng = ecx.machine.rng.get_mut();
541+
let return_nan = ecx.machine.float_nondet && rng.random() && exp.is_signaling();
550542
// Handle both the musl and glibc cases non-deterministically.
551-
if !exp.is_signaling() || rng.random() { one } else { random_nan(rng) }
543+
if return_nan { ecx.generate_nan(args) } else { one }
552544
}
553545

554546
// x^(±0) = 1 for any x, even a NaN, *but* not a SNaN
555547
("powf32" | "powf64", [base, exp]) if exp.is_zero() => {
556548
let rng = ecx.machine.rng.get_mut();
549+
let return_nan = ecx.machine.float_nondet && rng.random() && base.is_signaling();
557550
// Handle both the musl and glibc cases non-deterministically.
558-
if !base.is_signaling() || rng.random() { one } else { random_nan(rng) }
551+
if return_nan { ecx.generate_nan(args) } else { one }
559552
}
560553

561554
// There are a lot of cases for fixed outputs according to the C Standard, but these are mainly INF or zero
@@ -576,9 +569,10 @@ fn fixed_powi_float_value<S: Semantics>(
576569
0 => {
577570
let one = IeeeFloat::<S>::one();
578571
let rng = ecx.machine.rng.get_mut();
572+
let return_nan = ecx.machine.float_nondet && rng.random() && base.is_signaling();
579573
Some(
580574
// Handle both the musl and glibc powf cases non-deterministically.
581-
if !base.is_signaling() || rng.random() { one } else { random_nan(rng) },
575+
if return_nan { ecx.generate_nan(&[base]) } else { one },
582576
)
583577
}
584578

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

Lines changed: 14 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1066,39 +1066,6 @@ pub fn libm() {
10661066
assert_eq!((-1f32).powf(f32::NEG_INFINITY), 1.0);
10671067
assert_eq!((-1f64).powf(f64::NEG_INFINITY), 1.0);
10681068

1069-
// Makes sure an operations returns both `1` and a `NaN` randomly.
1070-
macro_rules! test_snan_nondet {
1071-
($pow_op:expr) => {{
1072-
let mut nan_seen = false;
1073-
let mut one_seen = false;
1074-
1075-
for _ in 0..64 {
1076-
let res = $pow_op;
1077-
nan_seen |= res.is_nan();
1078-
one_seen |= res == 1.0;
1079-
1080-
// little speedup
1081-
if nan_seen && one_seen { break; };
1082-
}
1083-
1084-
let op_as_str = stringify!($pow_op);
1085-
1086-
assert!(nan_seen && one_seen, "{} should return both `NaN` or `1.0` randomly", op_as_str);
1087-
}};
1088-
}
1089-
1090-
// x^(SNaN) = (1 | NaN)
1091-
test_snan_nondet!(f32::powf(SNAN_F32, 0.0));
1092-
test_snan_nondet!(f64::powf(SNAN_F64, 0.0));
1093-
1094-
// 1^(SNaN) = (1 | NaN)
1095-
test_snan_nondet!(f32::powf(1.0, SNAN_F32));
1096-
test_snan_nondet!(f64::powf(1.0, SNAN_F64));
1097-
1098-
// same as powf (keep it consistent):
1099-
// x^(SNaN) = (1 | NaN)
1100-
test_snan_nondet!(f32::powi(SNAN_F32, 0));
1101-
test_snan_nondet!(f64::powi(SNAN_F64, 0));
11021069

11031070
assert_eq!(0f32.powi(10), 0.0);
11041071
assert_eq!(0f64.powi(100), 0.0);
@@ -1522,4 +1489,18 @@ fn test_non_determinism() {
15221489
test_operations_f32(12., 5.);
15231490
test_operations_f64(19., 11.);
15241491
test_operations_f128(25., 18.);
1492+
1493+
1494+
// x^(SNaN) = (1 | NaN)
1495+
ensure_nondet(|| f32::powf(SNAN_F32, 0.0));
1496+
ensure_nondet(|| f64::powf(SNAN_F64, 0.0));
1497+
1498+
// 1^(SNaN) = (1 | NaN)
1499+
ensure_nondet(|| f32::powf(1.0, SNAN_F32));
1500+
ensure_nondet(|| f64::powf(1.0, SNAN_F64));
1501+
1502+
// same as powf (keep it consistent):
1503+
// x^(SNaN) = (1 | NaN)
1504+
ensure_nondet(|| f32::powi(SNAN_F32, 0));
1505+
ensure_nondet(|| f64::powi(SNAN_F64, 0));
15251506
}

0 commit comments

Comments
 (0)