@@ -350,7 +350,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
350350 let f = this. read_scalar ( f) ?. to_f32 ( ) ?;
351351 let i = this. read_scalar ( i) ?. to_i32 ( ) ?;
352352
353- let res = fixed_powi_float_value ( f, i) . unwrap_or_else ( || {
353+ let res = fixed_powi_float_value ( this , f, i) . unwrap_or_else ( || {
354354 // Using host floats (but it's fine, this operation does not have guaranteed precision).
355355 let res = f. to_host ( ) . powi ( i) . to_soft ( ) ;
356356
@@ -368,7 +368,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
368368 let f = this. read_scalar ( f) ?. to_f64 ( ) ?;
369369 let i = this. read_scalar ( i) ?. to_i32 ( ) ?;
370370
371- let res = fixed_powi_float_value ( f, i) . unwrap_or_else ( || {
371+ let res = fixed_powi_float_value ( this , f, i) . unwrap_or_else ( || {
372372 // Using host floats (but it's fine, this operation does not have guaranteed precision).
373373 let res = f. to_host ( ) . powi ( i) . to_soft ( ) ;
374374
@@ -528,8 +528,8 @@ fn random_nan<S: Semantics>(rng: &mut StdRng) -> IeeeFloat<S> {
528528/// and the C standard leaves behavior for SNaNs unspecified.
529529///
530530/// Miri chooses to adhere to both implementations and returns either one of them non-deterministically.
531- fn fixed_float_value < ' tcx , S : Semantics > (
532- ecx : & mut MiriInterpCx < ' tcx > ,
531+ fn fixed_float_value < S : Semantics > (
532+ ecx : & mut MiriInterpCx < ' _ > ,
533533 intrinsic_name : & str ,
534534 args : & [ IeeeFloat < S > ] ,
535535) -> Option < IeeeFloat < S > > {
@@ -550,6 +550,7 @@ fn fixed_float_value<'tcx, S: Semantics>(
550550 // Handle both the musl and glibc cases non-deterministically.
551551 if !exp. is_signaling ( ) || rng. random ( ) { one } else { random_nan ( rng) }
552552 }
553+
553554 // x^(±0) = 1 for any x, even a NaN, *but* not a SNaN
554555 ( "powf32" | "powf64" , [ base, exp] ) if exp. is_zero ( ) => {
555556 // Handle both the musl and glibc cases non-deterministically.
@@ -569,13 +570,21 @@ fn fixed_float_value<'tcx, S: Semantics>(
569570
570571/// Returns `Some(output)` if `powi` (called `pown` in C) results in a fixed value specified in the C standard
571572/// (specifically, C23 annex F.10.4.6) when doing `base^exp`. Otherwise, returns `None`.
572- fn fixed_powi_float_value < S : Semantics > ( base : IeeeFloat < S > , exp : i32 ) -> Option < IeeeFloat < S > > {
573- match ( base. category ( ) , exp) {
574- // x^0 = 1, if x is not a Signaling NaN
575- // FIXME(#4286): The C ecosystem is inconsistent with handling sNaN's, some return 1 others propogate
576- // the NaN. We should return either 1 or the NaN non-deterministically here.
577- // But for now, just handle them all the same.
578- ( _, 0 ) => Some ( IeeeFloat :: < S > :: one ( ) ) ,
573+ // 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.
574+ fn fixed_powi_float_value < S : Semantics > (
575+ ecx : & mut MiriInterpCx < ' _ > ,
576+ base : IeeeFloat < S > ,
577+ exp : i32 ,
578+ ) -> Option < IeeeFloat < S > > {
579+ match exp {
580+ 0 => {
581+ let one = IeeeFloat :: < S > :: one ( ) ;
582+ let rng = ecx. machine . rng . get_mut ( ) ;
583+ Some (
584+ // Handle both the musl and glibc powf cases non-deterministically.
585+ if !base. is_signaling ( ) || rng. random ( ) { one } else { random_nan ( rng) } ,
586+ )
587+ }
579588
580589 _ => None ,
581590 }
0 commit comments