@@ -362,7 +362,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
362
362
let f = this. read_scalar ( f) ?. to_f32 ( ) ?;
363
363
let i = this. read_scalar ( i) ?. to_i32 ( ) ?;
364
364
365
- let res = fixed_powi_float_value ( f, i) . unwrap_or_else ( || {
365
+ let res = fixed_powi_float_value ( this , f, i) . unwrap_or_else ( || {
366
366
// Using host floats (but it's fine, this operation does not have guaranteed precision).
367
367
let res = f. to_host ( ) . powi ( i) . to_soft ( ) ;
368
368
@@ -380,7 +380,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
380
380
let f = this. read_scalar ( f) ?. to_f64 ( ) ?;
381
381
let i = this. read_scalar ( i) ?. to_i32 ( ) ?;
382
382
383
- let res = fixed_powi_float_value ( f, i) . unwrap_or_else ( || {
383
+ let res = fixed_powi_float_value ( this , f, i) . unwrap_or_else ( || {
384
384
// Using host floats (but it's fine, this operation does not have guaranteed precision).
385
385
let res = f. to_host ( ) . powi ( i) . to_soft ( ) ;
386
386
@@ -540,8 +540,8 @@ fn random_nan<S: Semantics>(rng: &mut StdRng) -> IeeeFloat<S> {
540
540
/// and the C standard leaves behavior for SNaNs unspecified.
541
541
///
542
542
/// Miri chooses to adhere to both implementations and returns either one of them non-deterministically.
543
- fn fixed_float_value < ' tcx , S : Semantics > (
544
- ecx : & mut MiriInterpCx < ' tcx > ,
543
+ fn fixed_float_value < S : Semantics > (
544
+ ecx : & mut MiriInterpCx < ' _ > ,
545
545
intrinsic_name : & str ,
546
546
args : & [ IeeeFloat < S > ] ,
547
547
) -> Option < IeeeFloat < S > > {
@@ -562,6 +562,7 @@ fn fixed_float_value<'tcx, S: Semantics>(
562
562
// Handle both the musl and glibc cases non-deterministically.
563
563
if !exp. is_signaling ( ) || rng. random ( ) { one } else { random_nan ( rng) }
564
564
}
565
+
565
566
// x^(±0) = 1 for any x, even a NaN, *but* not a SNaN
566
567
( "powf32" | "powf64" , [ base, exp] ) if exp. is_zero ( ) => {
567
568
// Handle both the musl and glibc cases non-deterministically.
@@ -581,13 +582,21 @@ fn fixed_float_value<'tcx, S: Semantics>(
581
582
582
583
/// Returns `Some(output)` if `powi` (called `pown` in C) results in a fixed value specified in the C standard
583
584
/// (specifically, C23 annex F.10.4.6) when doing `base^exp`. Otherwise, returns `None`.
584
- fn fixed_powi_float_value < S : Semantics > ( base : IeeeFloat < S > , exp : i32 ) -> Option < IeeeFloat < S > > {
585
- match ( base. category ( ) , exp) {
586
- // x^0 = 1, if x is not a Signaling NaN
587
- // FIXME(#4286): The C ecosystem is inconsistent with handling sNaN's, some return 1 others propogate
588
- // the NaN. We should return either 1 or the NaN non-deterministically here.
589
- // But for now, just handle them all the same.
590
- ( _, 0 ) => Some ( IeeeFloat :: < S > :: one ( ) ) ,
585
+ // REVIEW: 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.
586
+ fn fixed_powi_float_value < S : Semantics > (
587
+ ecx : & mut MiriInterpCx < ' _ > ,
588
+ base : IeeeFloat < S > ,
589
+ exp : i32 ,
590
+ ) -> Option < IeeeFloat < S > > {
591
+ match exp {
592
+ 0 => {
593
+ let one = IeeeFloat :: < S > :: one ( ) ;
594
+ let rng = ecx. machine . rng . get_mut ( ) ;
595
+ Some (
596
+ // Handle both the musl and glibc powf cases non-deterministically.
597
+ if !base. is_signaling ( ) || rng. random ( ) { one } else { random_nan ( rng) } ,
598
+ )
599
+ }
591
600
592
601
_ => None ,
593
602
}
0 commit comments