diff options
Diffstat (limited to 'compiler')
| -rw-r--r-- | compiler/rustc_const_eval/src/interpret/intrinsics.rs | 16 | ||||
| -rw-r--r-- | compiler/rustc_const_eval/src/interpret/machine.rs | 6 |
2 files changed, 20 insertions, 2 deletions
diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs index 0664a882c1d..9f5f2533e08 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs @@ -747,7 +747,13 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { { let a: F = self.read_scalar(&args[0])?.to_float()?; let b: F = self.read_scalar(&args[1])?.to_float()?; - let res = self.adjust_nan(a.min(b), &[a, b]); + let res = if a == b { + // They are definitely not NaN (those are never equal), but they could be `+0` and `-0`. + // Let the machine decide which one to return. + M::equal_float_min_max(self, a, b) + } else { + self.adjust_nan(a.min(b), &[a, b]) + }; self.write_scalar(res, dest)?; interp_ok(()) } @@ -762,7 +768,13 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { { let a: F = self.read_scalar(&args[0])?.to_float()?; let b: F = self.read_scalar(&args[1])?.to_float()?; - let res = self.adjust_nan(a.max(b), &[a, b]); + let res = if a == b { + // They are definitely not NaN (those are never equal), but they could be `+0` and `-0`. + // Let the machine decide which one to return. + M::equal_float_min_max(self, a, b) + } else { + self.adjust_nan(a.max(b), &[a, b]) + }; self.write_scalar(res, dest)?; interp_ok(()) } diff --git a/compiler/rustc_const_eval/src/interpret/machine.rs b/compiler/rustc_const_eval/src/interpret/machine.rs index 36e5a2ff750..8f6b15b8df0 100644 --- a/compiler/rustc_const_eval/src/interpret/machine.rs +++ b/compiler/rustc_const_eval/src/interpret/machine.rs @@ -278,6 +278,12 @@ pub trait Machine<'tcx>: Sized { F2::NAN } + /// Determines the result of `min`/`max` on floats when the arguments are equal. + fn equal_float_min_max<F: Float>(_ecx: &InterpCx<'tcx, Self>, a: F, _b: F) -> F { + // By default, we pick the left argument. + a + } + /// Called before a basic block terminator is executed. #[inline] fn before_terminator(_ecx: &mut InterpCx<'tcx, Self>) -> InterpResult<'tcx> { |
