@@ -362,7 +362,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
362362 let f = this. read_scalar ( f) ?. to_f32 ( ) ?;
363363 let i = this. read_scalar ( i) ?. to_i32 ( ) ?;
364364
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 ( || {
366366 // Using host floats (but it's fine, this operation does not have guaranteed precision).
367367 let res = f. to_host ( ) . powi ( i) . to_soft ( ) ;
368368
@@ -380,7 +380,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
380380 let f = this. read_scalar ( f) ?. to_f64 ( ) ?;
381381 let i = this. read_scalar ( i) ?. to_i32 ( ) ?;
382382
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 ( || {
384384 // Using host floats (but it's fine, this operation does not have guaranteed precision).
385385 let res = f. to_host ( ) . powi ( i) . to_soft ( ) ;
386386
@@ -540,8 +540,8 @@ fn random_nan<S: Semantics>(rng: &mut StdRng) -> IeeeFloat<S> {
540540/// and the C standard leaves behavior for SNaNs unspecified.
541541///
542542/// 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 < ' _ > ,
545545 intrinsic_name : & str ,
546546 args : & [ IeeeFloat < S > ] ,
547547) -> Option < IeeeFloat < S > > {
@@ -562,6 +562,7 @@ fn fixed_float_value<'tcx, S: Semantics>(
562562 // Handle both the musl and glibc cases non-deterministically.
563563 if !exp. is_signaling ( ) || rng. random ( ) { one } else { random_nan ( rng) }
564564 }
565+
565566 // x^(±0) = 1 for any x, even a NaN, *but* not a SNaN
566567 ( "powf32" | "powf64" , [ base, exp] ) if exp. is_zero ( ) => {
567568 // Handle both the musl and glibc cases non-deterministically.
@@ -581,13 +582,21 @@ fn fixed_float_value<'tcx, S: Semantics>(
581582
582583/// Returns `Some(output)` if `powi` (called `pown` in C) results in a fixed value specified in the C standard
583584/// (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+ }
591600
592601 _ => None ,
593602 }
0 commit comments