@@ -8,7 +8,7 @@ use std::ops::Neg;
8
8
use rand:: Rng ;
9
9
use rustc_abi:: Size ;
10
10
use rustc_apfloat:: ieee:: { Double , IeeeFloat , Semantics , Single } ;
11
- use rustc_apfloat:: { self , Category , Float , Round } ;
11
+ use rustc_apfloat:: { self , Float , Round } ;
12
12
use rustc_middle:: mir;
13
13
use rustc_middle:: ty:: { self , FloatTy , ScalarInt } ;
14
14
use rustc_span:: { Symbol , sym} ;
@@ -19,6 +19,63 @@ use self::simd::EvalContextExt as _;
19
19
use crate :: math:: { IeeeExt , apply_random_float_error_ulp} ;
20
20
use crate :: * ;
21
21
22
+ macro_rules! pow_impl {
23
+ ( $this: expr, powf( $f1: expr, $f2: expr) ) => { {
24
+ let host1 = $f1. to_host( ) ;
25
+ let host2 = $f2. to_host( ) ;
26
+
27
+ let fixed_res = match ( host1, host2) {
28
+ // 1^y = 1 for any y even a NaN.
29
+ ( one @ 1.0 , _) => Some ( one) ,
30
+
31
+ // (-1)^(±INF) = 1
32
+ ( -1.0 , exp) if exp. is_infinite( ) => Some ( 1.0 ) ,
33
+
34
+ // x^(±0) = 1 for any x, even a NaN
35
+ ( _, 0.0 ) => Some ( 1.0 ) ,
36
+
37
+ _ => None ,
38
+ } ;
39
+ fixed_res. map_or_else( || {
40
+ // Using host floats (but it's fine, this operation does not have guaranteed precision).
41
+ let res = host1. powf( host2) . to_soft( ) ;
42
+ // Apply a relative error of 4ULP to introduce some non-determinism
43
+ // simulating imprecise implementations and optimizations.
44
+ apply_random_float_error_ulp(
45
+ $this, res, 2 , // log2(4)
46
+ )
47
+ } , ToSoft :: to_soft)
48
+ } } ;
49
+ ( $this: expr, powi( $f: expr, $i: expr) ) => { {
50
+ let host = $f. to_host( ) ;
51
+ let exp = $i;
52
+
53
+ let fixed_res = match ( host, exp) {
54
+ // ±0^x = ±0 with x an odd integer.
55
+ ( zero @ 0.0 , x) if x % 2 != 0 => Some ( zero) , // preserve sign of zero.
56
+
57
+ // ±0^x = +0 with x an even integer.
58
+ ( 0.0 , x) if x % 2 == 0 => Some ( 0.0 ) ,
59
+
60
+ // x^0 = 1:
61
+ // Standard specifies we can only fix to 1 if x is is not a Signaling NaN.
62
+ // TODO: How to do this in normal rust?
63
+ ( _, 0 ) /* if !f.is_signaling() */ => Some ( 1.0 ) ,
64
+
65
+ _ => None ,
66
+ } ;
67
+ fixed_res. map_or_else( || {
68
+ // Using host floats (but it's fine, this operation does not have guaranteed precision).
69
+ let res = host. powi( exp) . to_soft( ) ;
70
+ // Apply a relative error of 4ULP to introduce some non-determinism
71
+ // simulating imprecise implementations and optimizations.
72
+ apply_random_float_error_ulp(
73
+ $this, res, 2 , // log2(4)
74
+ )
75
+ } , ToSoft :: to_soft)
76
+ } } ;
77
+ }
78
+
22
79
impl < ' tcx > EvalContextExt < ' tcx > for crate :: MiriInterpCx < ' tcx > { }
23
80
pub trait EvalContextExt < ' tcx > : crate :: MiriInterpCxExt < ' tcx > {
24
81
fn call_intrinsic (
@@ -385,28 +442,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
385
442
let f1 = this. read_scalar ( f1) ?. to_f32 ( ) ?;
386
443
let f2 = this. read_scalar ( f2) ?. to_f32 ( ) ?;
387
444
388
- let fixed_res = match ( f1. category ( ) , f2. category ( ) ) {
389
- // 1^y = 1 for any y, even a NaN.
390
- ( Category :: Normal , _) if f1 == 1.0f32 . to_soft ( ) => Some ( 1.0f32 . to_soft ( ) ) ,
391
-
392
- // (-1)^(±INF) = 1
393
- ( Category :: Normal , Category :: Infinity ) if f1 == ( -1.0f32 ) . to_soft ( ) =>
394
- Some ( 1.0f32 . to_soft ( ) ) ,
395
-
396
- // x^(±0) = 1 for any x, even a NaN
397
- ( _, Category :: Zero ) => Some ( 1.0f32 . to_soft ( ) ) ,
398
-
399
- _ => None ,
400
- } ;
401
- let res = fixed_res. unwrap_or_else ( || {
402
- // Using host floats (but it's fine, this operation does not have guaranteed precision).
403
- let res = f1. to_host ( ) . powf ( f2. to_host ( ) ) . to_soft ( ) ;
404
- // Apply a relative error of 4ULP to introduce some non-determinism
405
- // simulating imprecise implementations and optimizations.
406
- apply_random_float_error_ulp (
407
- this, res, 2 , // log2(4)
408
- )
409
- } ) ;
445
+ let res = pow_impl ! ( this, powf( f1, f2) ) ;
410
446
let res = this. adjust_nan ( res, & [ f1, f2] ) ;
411
447
this. write_scalar ( res, dest) ?;
412
448
}
@@ -415,30 +451,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
415
451
let f1 = this. read_scalar ( f1) ?. to_f64 ( ) ?;
416
452
let f2 = this. read_scalar ( f2) ?. to_f64 ( ) ?;
417
453
418
- let fixed_res = match ( f1. category ( ) , f2. category ( ) ) {
419
- // 1^y = 1 for any y even a NaN.
420
- ( Category :: Normal , _) if f1 == 1.0f64 . to_soft ( ) => Some ( 1.0f64 . to_soft ( ) ) ,
421
-
422
- // (-1)^(±INF) = 1
423
- ( Category :: Normal , Category :: Infinity ) if f1 == ( -1.0f64 ) . to_soft ( ) =>
424
- Some ( 1.0f64 . to_soft ( ) ) ,
425
-
426
- // x^(±0) = 1 for any x, even a NaN
427
- ( _, Category :: Zero ) => Some ( 1.0f64 . to_soft ( ) ) ,
428
-
429
- // TODO: pow has a lot of "edge" cases which mostly result in ±0 or ±INF
430
- // do we have to catch them all?
431
- _ => None ,
432
- } ;
433
- let res = fixed_res. unwrap_or_else ( || {
434
- // Using host floats (but it's fine, this operation does not have guaranteed precision).
435
- let res = f1. to_host ( ) . powf ( f2. to_host ( ) ) . to_soft ( ) ;
436
- // Apply a relative error of 4ULP to introduce some non-determinism
437
- // simulating imprecise implementations and optimizations.
438
- apply_random_float_error_ulp (
439
- this, res, 2 , // log2(4)
440
- )
441
- } ) ;
454
+ let res = pow_impl ! ( this, powf( f1, f2) ) ;
442
455
let res = this. adjust_nan ( res, & [ f1, f2] ) ;
443
456
this. write_scalar ( res, dest) ?;
444
457
}
@@ -448,27 +461,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
448
461
let f = this. read_scalar ( f) ?. to_f32 ( ) ?;
449
462
let i = this. read_scalar ( i) ?. to_i32 ( ) ?;
450
463
451
- let fixed_res = match ( f. category ( ) , i) {
452
- // Standard specifies we can only fix to 1 if input is is not a Signaling NaN.
453
- ( _, 0 ) if !f. is_signaling ( ) => Some ( 1.0f32 . to_soft ( ) ) ,
454
-
455
- // TODO: Isn't this done by the implementation? And ULP error on 0.0 doesn't have an effect
456
- ( Category :: Zero , x) if x % 2 == 0 => Some ( 0.0f32 . to_soft ( ) ) ,
457
-
458
- // ±0^x = ±0 with x an odd integer.
459
- ( Category :: Zero , x) if x % 2 != 0 => Some ( f) , // preserve sign of zero.
460
- _ => None ,
461
- } ;
462
- let res = fixed_res. unwrap_or_else ( || {
463
- // Using host floats (but it's fine, this operation does not have guaranteed precision).
464
- let res = f. to_host ( ) . powi ( i) . to_soft ( ) ;
465
-
466
- // Apply a relative error of 4ULP to introduce some non-determinism
467
- // simulating imprecise implementations and optimizations.
468
- apply_random_float_error_ulp (
469
- this, res, 2 , // log2(4)
470
- )
471
- } ) ;
464
+ let res = pow_impl ! ( this, powi( f, i) ) ;
472
465
let res = this. adjust_nan ( res, & [ f] ) ;
473
466
this. write_scalar ( res, dest) ?;
474
467
}
@@ -477,28 +470,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
477
470
let f = this. read_scalar ( f) ?. to_f64 ( ) ?;
478
471
let i = this. read_scalar ( i) ?. to_i32 ( ) ?;
479
472
480
- let fixed_res = match ( f. category ( ) , i) {
481
- // Standard specifies we can only fix to 1 if input is is not a Signaling NaN.
482
- ( _, 0 ) if !f. is_signaling ( ) => Some ( 1.0f64 . to_soft ( ) ) ,
483
-
484
- // ±0^x = 0 with x an even integer.
485
- // TODO: Isn't this done by the implementation itself?
486
- ( Category :: Zero , x) if x % 2 == 0 => Some ( 0.0f64 . to_soft ( ) ) ,
487
-
488
- // ±0^x = ±0 with x an odd integer.
489
- ( Category :: Zero , x) if x % 2 != 0 => Some ( f) , // preserve sign of zero.
490
- _ => None ,
491
- } ;
492
- let res = fixed_res. unwrap_or_else ( || {
493
- // Using host floats (but it's fine, this operation does not have guaranteed precision).
494
- let res = f. to_host ( ) . powi ( i) . to_soft ( ) ;
495
-
496
- // Apply a relative error of 4ULP to introduce some non-determinism
497
- // simulating imprecise implementations and optimizations.
498
- apply_random_float_error_ulp (
499
- this, res, 2 , // log2(4)
500
- )
501
- } ) ;
473
+ let res = pow_impl ! ( this, powi( f, i) ) ;
502
474
let res = this. adjust_nan ( res, & [ f] ) ;
503
475
this. write_scalar ( res, dest) ?;
504
476
}
0 commit comments