@@ -17,7 +17,6 @@ use self::atomic::EvalContextExt as _;
1717use self :: helpers:: { ToHost , ToSoft , check_intrinsic_arg_count} ;
1818use self :: simd:: EvalContextExt as _;
1919use crate :: math:: { IeeeExt , apply_random_float_error_ulp} ;
20- use crate :: operator:: EvalContextExt as _;
2120use crate :: * ;
2221
2322impl < ' tcx > EvalContextExt < ' tcx > for crate :: MiriInterpCx < ' tcx > { }
@@ -535,49 +534,50 @@ fn fixed_float_value<S: Semantics>(
535534 // (-1)^(±INF) = 1
536535 ( "powf32" | "powf64" , [ base, exp] ) if * base == -one && exp. is_infinite ( ) => one,
537536
538- // 1^y = 1 for any y, even a NaN, *but* not a SNaN
537+ // 1^y = 1 for any y, even a NaN
539538 ( "powf32" | "powf64" , [ base, exp] ) if * base == one => {
540539 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 ( ) ;
542542 // Handle both the musl and glibc cases non-deterministically.
543543 if return_nan { ecx. generate_nan ( args) } else { one }
544544 }
545545
546- // x^(±0) = 1 for any x, even a NaN, *but* not a SNaN
546+ // x^(±0) = 1 for any x, even a NaN
547547 ( "powf32" | "powf64" , [ base, exp] ) if exp. is_zero ( ) => {
548548 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 ( ) ;
550551 // Handle both the musl and glibc cases non-deterministically.
551552 if return_nan { ecx. generate_nan ( args) } else { one }
552553 }
553554
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.
556557 _ => return None ,
557558 } )
558559}
559560
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`.
563563fn fixed_powi_float_value < S : Semantics > (
564564 ecx : & mut MiriInterpCx < ' _ > ,
565565 base : IeeeFloat < S > ,
566566 exp : i32 ,
567567) -> Option < IeeeFloat < S > > {
568- match exp {
568+ Some ( match exp {
569569 0 => {
570570 let one = IeeeFloat :: < S > :: one ( ) ;
571571 let rng = ecx. machine . rng . get_mut ( ) ;
572572 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 }
577577 }
578578
579- _ => None ,
580- }
579+ _ => return None ,
580+ } )
581581}
582582
583583/// Given an floating-point operation and a floating-point value, clamps the result to the output
0 commit comments