Skip to content

Commit

Permalink
apply requested changes of reviewer
Browse files Browse the repository at this point in the history
  • Loading branch information
LorrensP-2158466 committed Feb 8, 2025
1 parent 8c88114 commit 064357f
Show file tree
Hide file tree
Showing 4 changed files with 184 additions and 160 deletions.
100 changes: 45 additions & 55 deletions src/intrinsics/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@ use rand::Rng;
use rustc_abi::Size;
use rustc_apfloat::{Float, Round};
use rustc_middle::mir;
use rustc_middle::ty::{self, FloatTy};
use rustc_middle::ty::{self, FloatTy, ScalarInt};
use rustc_span::{Symbol, sym};

use self::atomic::EvalContextExt as _;
use self::helpers::{ToHost, ToSoft, check_intrinsic_arg_count};
use self::simd::EvalContextExt as _;
use crate::math::{apply_random_float_error, ulp_err_scale};
use crate::math::apply_random_float_error_ulp;
use crate::*;

impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {}
Expand Down Expand Up @@ -248,11 +248,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
"log2f32" => host.log2(),
_ => bug!(),
};
// Apply a relative error of 16ULP to simulate non-determinism
let res = apply_random_float_error(
let res = res.to_soft();
// Apply a relative error of 16ULP to introduce some non-determinism
// simulating imprecise implementations and optimizations.
let res = apply_random_float_error_ulp(
this,
res.to_soft(),
ulp_err_scale::<rustc_apfloat::ieee::Single>(4)
res,
4
);
let res = this.adjust_nan(res, &[f]);
this.write_scalar(res, dest)?;
Expand Down Expand Up @@ -281,11 +283,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
"log2f64" => host.log2(),
_ => bug!(),
};
// Apply a relative error of 16ULP to simulate non-determinism
let res = apply_random_float_error(
let res = res.to_soft();
// Apply a relative error of 16ULP to introduce some non-determinism
// simulating imprecise implementations and optimizations.
let res = apply_random_float_error_ulp(
this,
res.to_soft(),
ulp_err_scale::<rustc_apfloat::ieee::Double>(4));
res,
4
);
let res = this.adjust_nan(res, &[f]);
this.write_scalar(res, dest)?;
}
Expand Down Expand Up @@ -398,29 +403,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
"frem_algebraic" => mir::BinOp::Rem,
_ => bug!(),
};
// `binary_op` already called `generate_nan` if needed.
let res = this.binary_op(op, &a, &b)?;
// `binary_op` already called `generate_nan` if needed
// Apply a relative error of 16ULP to simulate non-determinism
fn apply_error_and_write<'tcx, F: Float + Into<Scalar> >(
ecx: &mut MiriInterpCx<'tcx>,
res: F,
dest: &MPlaceTy<'tcx>
) -> InterpResult<'tcx> {
let res = apply_random_float_error(
ecx,
res,
ulp_err_scale::<F>(4)
);
ecx.write_scalar(res, dest)
}
let scalar = res.to_scalar_int()?;
match res.layout.ty.kind(){
ty::Float(FloatTy::F16) => apply_error_and_write(this, scalar.to_f16(), dest),
ty::Float(FloatTy::F32) => apply_error_and_write(this, scalar.to_f32(), dest),
ty::Float(FloatTy::F64) => apply_error_and_write(this, scalar.to_f64(), dest),
ty::Float(FloatTy::F128) => apply_error_and_write(this, scalar.to_f128(), dest),
_ => bug!("`{intrinsic_name}` intrinsic called with non-float input type")
}?;
// Apply a relative error of 16ULP to simulate non-deterministic precision loss
// due to optimizations.
let res = apply_random_float_error_to_imm(this, res)?;
this.write_immediate(*res, dest)?;
}

#[rustfmt::skip]
Expand Down Expand Up @@ -464,33 +452,16 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
),
_ => {}
}
// This cannot be a NaN so we also don't have to apply any non-determinism.
// (Also, `binary_op` already called `generate_nan` if needed.)
let res = this.binary_op(op, &a, &b)?;
if !float_finite(&res)? {
throw_ub_format!("`{intrinsic_name}` intrinsic produced non-finite value as result");
}
// Apply a relative error of 16ULP to simulate non-determinism
fn apply_error_and_write<'tcx, F: Float + Into<Scalar> >(
ecx: &mut MiriInterpCx<'tcx>,
res: F,
dest: &MPlaceTy<'tcx>
) -> InterpResult<'tcx> {
let res = apply_random_float_error(
ecx,
res,
ulp_err_scale::<F>(4)
);
ecx.write_scalar(res, dest)
}
// This cannot be a NaN so we also don't have to apply any non-determinism.
// (Also, `binary_op` already called `generate_nan` if needed.)
let scalar = res.to_scalar_int()?;
match res.layout.ty.kind(){
ty::Float(FloatTy::F16) => apply_error_and_write(this, scalar.to_f16(), dest),
ty::Float(FloatTy::F32) => apply_error_and_write(this, scalar.to_f32(), dest),
ty::Float(FloatTy::F64) => apply_error_and_write(this, scalar.to_f64(), dest),
ty::Float(FloatTy::F128) => apply_error_and_write(this, scalar.to_f128(), dest),
_ => bug!("`{intrinsic_name}` intrinsic called with non-float input type")
}?;
// Apply a relative error of 16ULP to simulate non-deterministic precision loss
// due to optimizations.
let res = apply_random_float_error_to_imm(this, res)?;
this.write_immediate(*res, dest)?;
}

"float_to_int_unchecked" => {
Expand Down Expand Up @@ -522,3 +493,22 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
interp_ok(EmulateItemResult::NeedsReturn)
}
}

/// Applies a random 16ULP floating point error to `val` and returns the new value.
/// Will fail if `val` is not a floating point number.
fn apply_random_float_error_to_imm<'tcx>(
ecx: &mut MiriInterpCx<'tcx>,
val: ImmTy<'tcx>,
) -> InterpResult<'tcx, ImmTy<'tcx>> {
let scalar = val.to_scalar_int()?;
let layout = val.layout;
let res: ScalarInt = match val.layout.ty.kind() {
ty::Float(FloatTy::F16) => apply_random_float_error_ulp(ecx, scalar.to_f16(), 4).into(),
ty::Float(FloatTy::F32) => apply_random_float_error_ulp(ecx, scalar.to_f32(), 4).into(),
ty::Float(FloatTy::F64) => apply_random_float_error_ulp(ecx, scalar.to_f64(), 4).into(),
ty::Float(FloatTy::F128) => apply_random_float_error_ulp(ecx, scalar.to_f128(), 4).into(),
_ => bug!("intrinsic called with non-float input type"),
};

interp_ok(ImmTy::from_scalar_int(res, layout))
}
31 changes: 21 additions & 10 deletions src/math.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,6 @@ use rand::Rng as _;
use rustc_apfloat::Float as _;
use rustc_apfloat::ieee::IeeeFloat;

/// Creates an error scale to pass to `apply_random_float_error` when applying a 2^n ULP error.
/// For example, if you want to apply a 16 ULP error, you should pass 4, because 2^4 = 16.
pub(crate) fn ulp_err_scale<F: rustc_apfloat::Float>(n: u32) -> i32 {
let n = i32::try_from(n)
.expect("`err_scale_for_ulp`: exponent is too large to create an error scale");
// we know this fits
let prec = i32::try_from(F::PRECISION).unwrap();
-(prec - n - 1)
}

/// Disturbes a floating-point result by a relative error in the range (-2^scale, 2^scale).
///
/// For a 2^N ULP error, you can use an `err_scale` of `-(F::PRECISION - 1 - N)`.
Expand All @@ -37,6 +27,27 @@ pub(crate) fn apply_random_float_error<F: rustc_apfloat::Float>(
(val * (F::from_u128(1).value + err).value).value
}

/// [`apply_random_float_error`] gives instructions to apply a 2^N ULP error.
/// This function implements these instructions such that applying a 2^N ULP error is less error prone.
/// So for a 2^N ULP error, you would pass N as the `ulp_exponent` argument.
pub(crate) fn apply_random_float_error_ulp<F: rustc_apfloat::Float>(
ecx: &mut crate::MiriInterpCx<'_>,
val: F,
ulp_exponent: u32,
) -> F {
apply_random_float_error(ecx, val, ulp_exponent_err_scale::<F>(ulp_exponent))
}

/// Creates an error scale to pass to `apply_random_float_error` when applying a 2^n ULP error.
/// For example, if you want to apply a 16 ULP error, you should pass 4, because 2^4 = 16.
pub(crate) fn ulp_exponent_err_scale<F: rustc_apfloat::Float>(n: u32) -> i32 {
let n = i32::try_from(n)
.expect("`err_scale_for_ulp`: exponent is too large to create an error scale");
// we know this fits
let prec = i32::try_from(F::PRECISION).unwrap();
-(prec - n - 1)
}

pub(crate) fn sqrt<S: rustc_apfloat::ieee::Semantics>(x: IeeeFloat<S>) -> IeeeFloat<S> {
match x.category() {
// preserve zero sign
Expand Down
47 changes: 22 additions & 25 deletions src/shims/foreign_items.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ use rustc_target::callconv::{Conv, FnAbi};
use self::helpers::{ToHost, ToSoft};
use super::alloc::EvalContextExt as _;
use super::backtrace::EvalContextExt as _;
use crate::math::ulp_err_scale;
use crate::*;

/// Type of dynamic symbols (for `dlsym` et al)
Expand Down Expand Up @@ -762,11 +761,12 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
"tgammaf" => f_host.gamma(),
_ => bug!(),
};
// Apply a relative error of 16ULP to simulate non-determinism
let res = math::apply_random_float_error(
// Apply a relative error of 16ULP to introduce some non-determinism
// simulating imprecise implementations and optimizations.
let res = math::apply_random_float_error_ulp(
this,
res.to_soft(),
ulp_err_scale::<rustc_apfloat::ieee::Single>(4),
4
);
let res = this.adjust_nan(res, &[f]);
this.write_scalar(res, dest)?;
Expand All @@ -790,11 +790,12 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
"fdimf" => f1.to_host().abs_sub(f2.to_host()).to_soft(),
_ => bug!(),
};
// Apply a relative error of 16ULP to simulate non-determinism
let res = math::apply_random_float_error(
// Apply a relative error of 16ULP to introduce some non-determinism
// simulating imprecise implementations and optimizations.
let res = math::apply_random_float_error_ulp(
this,
res,
ulp_err_scale::<rustc_apfloat::ieee::Single>(4),
4
);
let res = this.adjust_nan(res, &[f1, f2]);
this.write_scalar(res, dest)?;
Expand Down Expand Up @@ -830,11 +831,12 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
"tgamma" => f_host.gamma(),
_ => bug!(),
};
// Apply a relative error of 16ULP to simulate non-determinism
let res = math::apply_random_float_error(
// Apply a relative error of 16ULP to introduce some non-determinism
// simulating imprecise implementations and optimizations.
let res = math::apply_random_float_error_ulp(
this,
res.to_soft(),
ulp_err_scale::<rustc_apfloat::ieee::Double>(4),
4
);
let res = this.adjust_nan(res, &[f]);
this.write_scalar(res, dest)?;
Expand All @@ -858,11 +860,12 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
"fdim" => f1.to_host().abs_sub(f2.to_host()).to_soft(),
_ => bug!(),
};
// Apply a relative error of 16ULP to simulate non-determinism
let res = math::apply_random_float_error(
// Apply a relative error of 16ULP to introduce some non-determinism
// simulating imprecise implementations and optimizations.
let res = math::apply_random_float_error_ulp(
this,
res,
ulp_err_scale::<rustc_apfloat::ieee::Double>(4),
4
);
let res = this.adjust_nan(res, &[f1, f2]);
this.write_scalar(res, dest)?;
Expand All @@ -889,12 +892,9 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
// Using host floats (but it's fine, these operations do not have guaranteed precision).
let (res, sign) = x.to_host().ln_gamma();
this.write_int(sign, &signp)?;
// Apply a relative error of 16ULP to simulate non-determinism
let res = math::apply_random_float_error(
this,
res.to_soft(),
ulp_err_scale::<rustc_apfloat::ieee::Single>(4),
);
// Apply a relative error of 16ULP to introduce some non-determinism
// simulating imprecise implementations and optimizations.
let res = math::apply_random_float_error_ulp(this, res.to_soft(), 4);
let res = this.adjust_nan(res, &[x]);
this.write_scalar(res, dest)?;
}
Expand All @@ -906,12 +906,9 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
// Using host floats (but it's fine, these operations do not have guaranteed precision).
let (res, sign) = x.to_host().ln_gamma();
this.write_int(sign, &signp)?;
// Apply a relative error of 16ULP to simulate non-determinism
let res = math::apply_random_float_error(
this,
res.to_soft(),
ulp_err_scale::<rustc_apfloat::ieee::Double>(4),
);
// Apply a relative error of 16ULP to introduce some non-determinism
// simulating imprecise implementations and optimizations.
let res = math::apply_random_float_error_ulp(this, res.to_soft(), 4);
let res = this.adjust_nan(res, &[x]);
this.write_scalar(res, dest)?;
}
Expand Down
Loading

0 comments on commit 064357f

Please sign in to comment.