Skip to content

Commit acbc681

Browse files
authored
Merge pull request #4398 from rust-lang/rustup-2025-06-14
Automatic Rustup
2 parents ab56b52 + 445a2d2 commit acbc681

File tree

9 files changed

+38
-23
lines changed

9 files changed

+38
-23
lines changed

README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,11 @@ environment variable. We first document the most relevant and most commonly used
286286
specific circumstances, but Miri's behavior will also be more stable across versions and targets.
287287
This is equivalent to `-Zmiri-fixed-schedule -Zmiri-compare-exchange-weak-failure-rate=0.0
288288
-Zmiri-address-reuse-cross-thread-rate=0.0 -Zmiri-disable-weak-memory-emulation`.
289+
* `-Zmiri-deterministic-floats` makes Miri's floating-point behavior fully deterministic. This means
290+
that operations will always return the preferred NaN, imprecise operations will not have any
291+
random error applied to them, and `min`/`max` as "maybe fused" multiply-add all behave
292+
deterministically. Note that Miri still uses host floats for some operations, so behavior can
293+
still differ depending on the host target and setup.
289294
* `-Zmiri-disable-isolation` disables host isolation. As a consequence,
290295
the program has access to host resources such as environment variables, file
291296
systems, and randomness.

rust-version

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
c6768de2d63de7a41124a0fb8fc78f9e26111c01
1+
d087f112b7d1323446c7b39a8b616aee7fa56b3d

src/bin/miri.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -601,6 +601,8 @@ fn main() {
601601
miri_config.collect_leak_backtraces = false;
602602
} else if arg == "-Zmiri-force-intrinsic-fallback" {
603603
miri_config.force_intrinsic_fallback = true;
604+
} else if arg == "-Zmiri-deterministic-floats" {
605+
miri_config.float_nondet = false;
604606
} else if arg == "-Zmiri-strict-provenance" {
605607
miri_config.provenance_mode = ProvenanceMode::Strict;
606608
} else if arg == "-Zmiri-permissive-provenance" {

src/eval.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,8 @@ pub struct MiriConfig {
166166
pub fixed_scheduling: bool,
167167
/// Always prefer the intrinsic fallback body over the native Miri implementation.
168168
pub force_intrinsic_fallback: bool,
169+
/// Whether floating-point operations can behave non-deterministically.
170+
pub float_nondet: bool,
169171
}
170172

171173
impl Default for MiriConfig {
@@ -205,6 +207,7 @@ impl Default for MiriConfig {
205207
address_reuse_cross_thread_rate: 0.1,
206208
fixed_scheduling: false,
207209
force_intrinsic_fallback: false,
210+
float_nondet: true,
208211
}
209212
}
210213
}

src/intrinsics/mod.rs

Lines changed: 6 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -272,8 +272,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
272272
let a = this.read_scalar(a)?.to_f32()?;
273273
let b = this.read_scalar(b)?.to_f32()?;
274274
let c = this.read_scalar(c)?.to_f32()?;
275-
// FIXME: Using host floats, to work around https://github.com/rust-lang/rustc_apfloat/issues/11
276-
let res = a.to_host().mul_add(b.to_host(), c.to_host()).to_soft();
275+
let res = a.mul_add(b, c).value;
277276
let res = this.adjust_nan(res, &[a, b, c]);
278277
this.write_scalar(res, dest)?;
279278
}
@@ -282,8 +281,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
282281
let a = this.read_scalar(a)?.to_f64()?;
283282
let b = this.read_scalar(b)?.to_f64()?;
284283
let c = this.read_scalar(c)?.to_f64()?;
285-
// FIXME: Using host floats, to work around https://github.com/rust-lang/rustc_apfloat/issues/11
286-
let res = a.to_host().mul_add(b.to_host(), c.to_host()).to_soft();
284+
let res = a.mul_add(b, c).value;
287285
let res = this.adjust_nan(res, &[a, b, c]);
288286
this.write_scalar(res, dest)?;
289287
}
@@ -293,13 +291,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
293291
let a = this.read_scalar(a)?.to_f32()?;
294292
let b = this.read_scalar(b)?.to_f32()?;
295293
let c = this.read_scalar(c)?.to_f32()?;
296-
let fuse: bool = this.machine.rng.get_mut().random();
297-
let res = if fuse {
298-
// FIXME: Using host floats, to work around https://github.com/rust-lang/rustc_apfloat/issues/11
299-
a.to_host().mul_add(b.to_host(), c.to_host()).to_soft()
300-
} else {
301-
((a * b).value + c).value
302-
};
294+
let fuse: bool = this.machine.float_nondet && this.machine.rng.get_mut().random();
295+
let res = if fuse { a.mul_add(b, c).value } else { ((a * b).value + c).value };
303296
let res = this.adjust_nan(res, &[a, b, c]);
304297
this.write_scalar(res, dest)?;
305298
}
@@ -308,13 +301,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
308301
let a = this.read_scalar(a)?.to_f64()?;
309302
let b = this.read_scalar(b)?.to_f64()?;
310303
let c = this.read_scalar(c)?.to_f64()?;
311-
let fuse: bool = this.machine.rng.get_mut().random();
312-
let res = if fuse {
313-
// FIXME: Using host floats, to work around https://github.com/rust-lang/rustc_apfloat/issues/11
314-
a.to_host().mul_add(b.to_host(), c.to_host()).to_soft()
315-
} else {
316-
((a * b).value + c).value
317-
};
304+
let fuse: bool = this.machine.float_nondet && this.machine.rng.get_mut().random();
305+
let res = if fuse { a.mul_add(b, c).value } else { ((a * b).value + c).value };
318306
let res = this.adjust_nan(res, &[a, b, c]);
319307
this.write_scalar(res, dest)?;
320308
}

src/intrinsics/simd.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -306,7 +306,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
306306
let c = this.read_scalar(&this.project_index(&c, i)?)?;
307307
let dest = this.project_index(&dest, i)?;
308308

309-
let fuse: bool = intrinsic_name == "fma" || this.machine.rng.get_mut().random();
309+
let fuse: bool = intrinsic_name == "fma"
310+
|| (this.machine.float_nondet && this.machine.rng.get_mut().random());
310311

311312
// Works for f32 and f64.
312313
// FIXME: using host floats to work around https://github.com/rust-lang/miri/issues/2468.
@@ -320,7 +321,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
320321
let b = b.to_f32()?;
321322
let c = c.to_f32()?;
322323
let res = if fuse {
323-
a.to_host().mul_add(b.to_host(), c.to_host()).to_soft()
324+
a.mul_add(b, c).value
324325
} else {
325326
((a * b).value + c).value
326327
};
@@ -332,7 +333,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
332333
let b = b.to_f64()?;
333334
let c = c.to_f64()?;
334335
let res = if fuse {
335-
a.to_host().mul_add(b.to_host(), c.to_host()).to_soft()
336+
a.mul_add(b, c).value
336337
} else {
337338
((a * b).value + c).value
338339
};

src/machine.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -618,6 +618,9 @@ pub struct MiriMachine<'tcx> {
618618

619619
/// Always prefer the intrinsic fallback body over the native Miri implementation.
620620
pub force_intrinsic_fallback: bool,
621+
622+
/// Whether floating-point operations can behave non-deterministically.
623+
pub float_nondet: bool,
621624
}
622625

623626
impl<'tcx> MiriMachine<'tcx> {
@@ -778,6 +781,7 @@ impl<'tcx> MiriMachine<'tcx> {
778781
int2ptr_warned: Default::default(),
779782
mangle_internal_symbol_cache: Default::default(),
780783
force_intrinsic_fallback: config.force_intrinsic_fallback,
784+
float_nondet: config.float_nondet,
781785
}
782786
}
783787

@@ -956,6 +960,7 @@ impl VisitProvenance for MiriMachine<'_> {
956960
int2ptr_warned: _,
957961
mangle_internal_symbol_cache: _,
958962
force_intrinsic_fallback: _,
963+
float_nondet: _,
959964
} = self;
960965

961966
threads.visit_provenance(visit);

src/math.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,10 @@ pub(crate) fn apply_random_float_error<F: rustc_apfloat::Float>(
1515
val: F,
1616
err_scale: i32,
1717
) -> F {
18+
if !ecx.machine.float_nondet {
19+
return val;
20+
}
21+
1822
let rng = ecx.machine.rng.get_mut();
1923
// Generate a random integer in the range [0, 2^PREC).
2024
// (When read as binary, the position of the first `1` determines the exponent,

src/operator.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,11 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
7676
}
7777

7878
fn generate_nan<F1: Float + FloatConvert<F2>, F2: Float>(&self, inputs: &[F1]) -> F2 {
79+
let this = self.eval_context_ref();
80+
if !this.machine.float_nondet {
81+
return F2::NAN;
82+
}
83+
7984
/// Make the given NaN a signaling NaN.
8085
/// Returns `None` if this would not result in a NaN.
8186
fn make_signaling<F: Float>(f: F) -> Option<F> {
@@ -89,7 +94,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
8994
if f.is_nan() { Some(f) } else { None }
9095
}
9196

92-
let this = self.eval_context_ref();
9397
let mut rand = this.machine.rng.borrow_mut();
9498
// Assemble an iterator of possible NaNs: preferred, quieting propagation, unchanged propagation.
9599
// On some targets there are more possibilities; for now we just generate those options that
@@ -118,6 +122,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
118122

119123
fn equal_float_min_max<F: Float>(&self, a: F, b: F) -> F {
120124
let this = self.eval_context_ref();
125+
if !this.machine.float_nondet {
126+
return a;
127+
}
121128
// Return one side non-deterministically.
122129
let mut rand = this.machine.rng.borrow_mut();
123130
if rand.random() { a } else { b }

0 commit comments

Comments
 (0)