1
Fork 0

float-to-float casts also have non-deterministic NaN results

This commit is contained in:
Ralf Jung 2023-10-09 07:38:00 +02:00
parent 615d738abe
commit 08deb0daed
6 changed files with 150 additions and 17 deletions

View file

@ -311,6 +311,21 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
F: Float + Into<Scalar<M::Provenance>> + FloatConvert<Single> + FloatConvert<Double>,
{
use rustc_type_ir::sty::TyKind::*;
fn adjust_nan<
'mir,
'tcx: 'mir,
M: Machine<'mir, 'tcx>,
F1: rustc_apfloat::Float + FloatConvert<F2>,
F2: rustc_apfloat::Float,
>(
ecx: &InterpCx<'mir, 'tcx, M>,
f1: F1,
f2: F2,
) -> F2 {
if f2.is_nan() { M::generate_nan(ecx, &[f1]) } else { f2 }
}
match *dest_ty.kind() {
// float -> uint
Uint(t) => {
@ -330,9 +345,13 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
Scalar::from_int(v, size)
}
// float -> f32
Float(FloatTy::F32) => Scalar::from_f32(f.convert(&mut false).value),
Float(FloatTy::F32) => {
Scalar::from_f32(adjust_nan(self, f, f.convert(&mut false).value))
}
// float -> f64
Float(FloatTy::F64) => Scalar::from_f64(f.convert(&mut false).value),
Float(FloatTy::F64) => {
Scalar::from_f64(adjust_nan(self, f, f.convert(&mut false).value))
}
// That's it.
_ => span_bug!(self.cur_span(), "invalid float to {} cast", dest_ty),
}

View file

@ -6,7 +6,7 @@ use std::borrow::{Borrow, Cow};
use std::fmt::Debug;
use std::hash::Hash;
use rustc_apfloat::Float;
use rustc_apfloat::{Float, FloatConvert};
use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
use rustc_middle::mir;
use rustc_middle::ty::layout::TyAndLayout;
@ -243,9 +243,12 @@ pub trait Machine<'mir, 'tcx: 'mir>: Sized {
/// Generate the NaN returned by a float operation, given the list of inputs.
/// (This is all inputs, not just NaN inputs!)
fn generate_nan<F: Float>(_ecx: &InterpCx<'mir, 'tcx, Self>, _inputs: &[F]) -> F {
fn generate_nan<F1: Float + FloatConvert<F2>, F2: Float>(
_ecx: &InterpCx<'mir, 'tcx, Self>,
_inputs: &[F1],
) -> F2 {
// By default we always return the preferred NaN.
F::NAN
F2::NAN
}
/// Called before writing the specified `local` of the `frame`.

View file

@ -1,4 +1,4 @@
use rustc_apfloat::Float;
use rustc_apfloat::{Float, FloatConvert};
use rustc_middle::mir;
use rustc_middle::mir::interpret::{InterpResult, Scalar};
use rustc_middle::ty::layout::TyAndLayout;
@ -104,7 +104,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
(ImmTy::from_bool(res, *self.tcx), false)
}
fn binary_float_op<F: Float + Into<Scalar<M::Provenance>>>(
fn binary_float_op<F: Float + FloatConvert<F> + Into<Scalar<M::Provenance>>>(
&self,
bin_op: mir::BinOp,
layout: TyAndLayout<'tcx>,