@@ -7,13 +7,13 @@ use rand::Rng;
7
7
use rustc_abi:: Size ;
8
8
use rustc_apfloat:: { Float , Round } ;
9
9
use rustc_middle:: mir;
10
- use rustc_middle:: ty:: { self , FloatTy } ;
10
+ use rustc_middle:: ty:: { self , FloatTy , ScalarInt } ;
11
11
use rustc_span:: { Symbol , sym} ;
12
12
13
13
use self :: atomic:: EvalContextExt as _;
14
14
use self :: helpers:: { ToHost , ToSoft , check_intrinsic_arg_count} ;
15
15
use self :: simd:: EvalContextExt as _;
16
- use crate :: math:: { apply_random_float_error , ulp_err_scale } ;
16
+ use crate :: math:: apply_random_float_error_ulp ;
17
17
use crate :: * ;
18
18
19
19
impl < ' tcx > EvalContextExt < ' tcx > for crate :: MiriInterpCx < ' tcx > { }
@@ -248,11 +248,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
248
248
"log2f32" => host. log2 ( ) ,
249
249
_ => bug ! ( ) ,
250
250
} ;
251
- // Apply a relative error of 16ULP to simulate non-determinism
252
- let res = apply_random_float_error (
251
+ let res = res. to_soft ( ) ;
252
+ // Apply a relative error of 16ULP to introduce some non-determinism
253
+ // simulating imprecise implementations and optimizations.
254
+ let res = apply_random_float_error_ulp (
253
255
this,
254
- res. to_soft ( ) ,
255
- ulp_err_scale :: < rustc_apfloat :: ieee :: Single > ( 4 )
256
+ res,
257
+ 4
256
258
) ;
257
259
let res = this. adjust_nan ( res, & [ f] ) ;
258
260
this. write_scalar ( res, dest) ?;
@@ -281,11 +283,14 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
281
283
"log2f64" => host. log2 ( ) ,
282
284
_ => bug ! ( ) ,
283
285
} ;
284
- // Apply a relative error of 16ULP to simulate non-determinism
285
- let res = apply_random_float_error (
286
+ let res = res. to_soft ( ) ;
287
+ // Apply a relative error of 16ULP to introduce some non-determinism
288
+ // simulating imprecise implementations and optimizations.
289
+ let res = apply_random_float_error_ulp (
286
290
this,
287
- res. to_soft ( ) ,
288
- ulp_err_scale :: < rustc_apfloat:: ieee:: Double > ( 4 ) ) ;
291
+ res,
292
+ 4
293
+ ) ;
289
294
let res = this. adjust_nan ( res, & [ f] ) ;
290
295
this. write_scalar ( res, dest) ?;
291
296
}
@@ -398,29 +403,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
398
403
"frem_algebraic" => mir:: BinOp :: Rem ,
399
404
_ => bug ! ( ) ,
400
405
} ;
406
+ // `binary_op` already called `generate_nan` if needed.
401
407
let res = this. binary_op ( op, & a, & b) ?;
402
- // `binary_op` already called `generate_nan` if needed
403
- // Apply a relative error of 16ULP to simulate non-determinism
404
- fn apply_error_and_write < ' tcx , F : Float + Into < Scalar > > (
405
- ecx : & mut MiriInterpCx < ' tcx > ,
406
- res : F ,
407
- dest : & MPlaceTy < ' tcx >
408
- ) -> InterpResult < ' tcx > {
409
- let res = apply_random_float_error (
410
- ecx,
411
- res,
412
- ulp_err_scale :: < F > ( 4 )
413
- ) ;
414
- ecx. write_scalar ( res, dest)
415
- }
416
- let scalar = res. to_scalar_int ( ) ?;
417
- match res. layout . ty . kind ( ) {
418
- ty:: Float ( FloatTy :: F16 ) => apply_error_and_write ( this, scalar. to_f16 ( ) , dest) ,
419
- ty:: Float ( FloatTy :: F32 ) => apply_error_and_write ( this, scalar. to_f32 ( ) , dest) ,
420
- ty:: Float ( FloatTy :: F64 ) => apply_error_and_write ( this, scalar. to_f64 ( ) , dest) ,
421
- ty:: Float ( FloatTy :: F128 ) => apply_error_and_write ( this, scalar. to_f128 ( ) , dest) ,
422
- _ => bug ! ( "`{intrinsic_name}` intrinsic called with non-float input type" )
423
- } ?;
408
+ // Apply a relative error of 16ULP to simulate non-deterministic precision loss
409
+ // due to optimizations.
410
+ let res = apply_random_float_error_to_imm ( this, res) ?;
411
+ this. write_immediate ( * res, dest) ?;
424
412
}
425
413
426
414
#[ rustfmt:: skip]
@@ -464,33 +452,16 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
464
452
) ,
465
453
_ => { }
466
454
}
455
+ // This cannot be a NaN so we also don't have to apply any non-determinism.
456
+ // (Also, `binary_op` already called `generate_nan` if needed.)
467
457
let res = this. binary_op ( op, & a, & b) ?;
468
458
if !float_finite ( & res) ? {
469
459
throw_ub_format ! ( "`{intrinsic_name}` intrinsic produced non-finite value as result" ) ;
470
460
}
471
- // Apply a relative error of 16ULP to simulate non-determinism
472
- fn apply_error_and_write < ' tcx , F : Float + Into < Scalar > > (
473
- ecx : & mut MiriInterpCx < ' tcx > ,
474
- res : F ,
475
- dest : & MPlaceTy < ' tcx >
476
- ) -> InterpResult < ' tcx > {
477
- let res = apply_random_float_error (
478
- ecx,
479
- res,
480
- ulp_err_scale :: < F > ( 4 )
481
- ) ;
482
- ecx. write_scalar ( res, dest)
483
- }
484
- // This cannot be a NaN so we also don't have to apply any non-determinism.
485
- // (Also, `binary_op` already called `generate_nan` if needed.)
486
- let scalar = res. to_scalar_int ( ) ?;
487
- match res. layout . ty . kind ( ) {
488
- ty:: Float ( FloatTy :: F16 ) => apply_error_and_write ( this, scalar. to_f16 ( ) , dest) ,
489
- ty:: Float ( FloatTy :: F32 ) => apply_error_and_write ( this, scalar. to_f32 ( ) , dest) ,
490
- ty:: Float ( FloatTy :: F64 ) => apply_error_and_write ( this, scalar. to_f64 ( ) , dest) ,
491
- ty:: Float ( FloatTy :: F128 ) => apply_error_and_write ( this, scalar. to_f128 ( ) , dest) ,
492
- _ => bug ! ( "`{intrinsic_name}` intrinsic called with non-float input type" )
493
- } ?;
461
+ // Apply a relative error of 16ULP to simulate non-deterministic precision loss
462
+ // due to optimizations.
463
+ let res = apply_random_float_error_to_imm ( this, res) ?;
464
+ this. write_immediate ( * res, dest) ?;
494
465
}
495
466
496
467
"float_to_int_unchecked" => {
@@ -522,3 +493,22 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
522
493
interp_ok ( EmulateItemResult :: NeedsReturn )
523
494
}
524
495
}
496
+
497
+ /// Applies a random 16ULP floating point error to `val` and returns the new value.
498
+ /// Will fail if `val` is not a floating point number.
499
+ fn apply_random_float_error_to_imm < ' tcx > (
500
+ ecx : & mut MiriInterpCx < ' tcx > ,
501
+ val : ImmTy < ' tcx > ,
502
+ ) -> InterpResult < ' tcx , ImmTy < ' tcx > > {
503
+ let scalar = val. to_scalar_int ( ) ?;
504
+ let layout = val. layout ;
505
+ let res: ScalarInt = match val. layout . ty . kind ( ) {
506
+ ty:: Float ( FloatTy :: F16 ) => apply_random_float_error_ulp ( ecx, scalar. to_f16 ( ) , 4 ) . into ( ) ,
507
+ ty:: Float ( FloatTy :: F32 ) => apply_random_float_error_ulp ( ecx, scalar. to_f32 ( ) , 4 ) . into ( ) ,
508
+ ty:: Float ( FloatTy :: F64 ) => apply_random_float_error_ulp ( ecx, scalar. to_f64 ( ) , 4 ) . into ( ) ,
509
+ ty:: Float ( FloatTy :: F128 ) => apply_random_float_error_ulp ( ecx, scalar. to_f128 ( ) , 4 ) . into ( ) ,
510
+ _ => bug ! ( "intrinsic called with non-float input type" ) ,
511
+ } ;
512
+
513
+ interp_ok ( ImmTy :: from_scalar_int ( res, layout) )
514
+ }
0 commit comments