@@ -17,7 +17,6 @@ use self::atomic::EvalContextExt as _;
17
17
use self :: helpers:: { ToHost , ToSoft , check_intrinsic_arg_count} ;
18
18
use self :: simd:: EvalContextExt as _;
19
19
use crate :: math:: { IeeeExt , apply_random_float_error_ulp} ;
20
- use crate :: operator:: EvalContextExt as _;
21
20
use crate :: * ;
22
21
23
22
impl < ' tcx > EvalContextExt < ' tcx > for crate :: MiriInterpCx < ' tcx > { }
@@ -535,49 +534,50 @@ fn fixed_float_value<S: Semantics>(
535
534
// (-1)^(±INF) = 1
536
535
( "powf32" | "powf64" , [ base, exp] ) if * base == -one && exp. is_infinite ( ) => one,
537
536
538
- // 1^y = 1 for any y, even a NaN, *but* not a SNaN
537
+ // 1^y = 1 for any y, even a NaN
539
538
( "powf32" | "powf64" , [ base, exp] ) if * base == one => {
540
539
let rng = ecx. machine . rng . get_mut ( ) ;
541
- let return_nan = ecx. machine . float_nondet && rng. random ( ) && exp. is_signaling ( ) ;
540
+ // SNaN exponents get special treatment: they might return 1, or a NaN.
541
+ let return_nan = exp. is_signaling ( ) && ecx. machine . float_nondet && rng. random ( ) ;
542
542
// Handle both the musl and glibc cases non-deterministically.
543
543
if return_nan { ecx. generate_nan ( args) } else { one }
544
544
}
545
545
546
- // x^(±0) = 1 for any x, even a NaN, *but* not a SNaN
546
+ // x^(±0) = 1 for any x, even a NaN
547
547
( "powf32" | "powf64" , [ base, exp] ) if exp. is_zero ( ) => {
548
548
let rng = ecx. machine . rng . get_mut ( ) ;
549
- let return_nan = ecx. machine . float_nondet && rng. random ( ) && base. is_signaling ( ) ;
549
+ // SNaN bases get special treatment: they might return 1, or a NaN.
550
+ let return_nan = base. is_signaling ( ) && ecx. machine . float_nondet && rng. random ( ) ;
550
551
// Handle both the musl and glibc cases non-deterministically.
551
552
if return_nan { ecx. generate_nan ( args) } else { one }
552
553
}
553
554
554
- // There are a lot of cases for fixed outputs according to the C Standard, but these are mainly INF or zero
555
- // which are not affected by the applied error.
555
+ // There are a lot of cases for fixed outputs according to the C Standard, but these are
556
+ // mainly INF or zero which are not affected by the applied error.
556
557
_ => return None ,
557
558
} )
558
559
}
559
560
560
- /// Returns `Some(output)` if `powi` (called `pown` in C) results in a fixed value specified in the C standard
561
- /// (specifically, C23 annex F.10.4.6) when doing `base^exp`. Otherwise, returns `None`.
562
- // TODO: I'm not sure what I should document here about pown(1, SNaN) since musl and glibc do the same and the C standard is explicit here.
561
+ /// Returns `Some(output)` if `powi` (called `pown` in C) results in a fixed value specified in the
562
+ /// C standard (specifically, C23 annex F.10.4.6) when doing `base^exp`. Otherwise, returns `None`.
563
563
fn fixed_powi_float_value < S : Semantics > (
564
564
ecx : & mut MiriInterpCx < ' _ > ,
565
565
base : IeeeFloat < S > ,
566
566
exp : i32 ,
567
567
) -> Option < IeeeFloat < S > > {
568
- match exp {
568
+ Some ( match exp {
569
569
0 => {
570
570
let one = IeeeFloat :: < S > :: one ( ) ;
571
571
let rng = ecx. machine . rng . get_mut ( ) ;
572
572
let return_nan = ecx. machine . float_nondet && rng. random ( ) && base. is_signaling ( ) ;
573
- Some (
574
- // Handle both the musl and glibc powf cases non-deterministically.
575
- if return_nan { ecx . generate_nan ( & [ base ] ) } else { one } ,
576
- )
573
+ // For SNaN treatment, we are consistent with `powf`above.
574
+ // (We wouldn't have two, unlike powf all implementations seem to agree for powi,
575
+ // but for now we are maximally conservative.)
576
+ if return_nan { ecx . generate_nan ( & [ base ] ) } else { one }
577
577
}
578
578
579
- _ => None ,
580
- }
579
+ _ => return None ,
580
+ } )
581
581
}
582
582
583
583
/// Given an floating-point operation and a floating-point value, clamps the result to the output
0 commit comments