@@ -350,7 +350,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
350
350
let f = this. read_scalar ( f) ?. to_f32 ( ) ?;
351
351
let i = this. read_scalar ( i) ?. to_i32 ( ) ?;
352
352
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 ( || {
354
354
// Using host floats (but it's fine, this operation does not have guaranteed precision).
355
355
let res = f. to_host ( ) . powi ( i) . to_soft ( ) ;
356
356
@@ -368,7 +368,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
368
368
let f = this. read_scalar ( f) ?. to_f64 ( ) ?;
369
369
let i = this. read_scalar ( i) ?. to_i32 ( ) ?;
370
370
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 ( || {
372
372
// Using host floats (but it's fine, this operation does not have guaranteed precision).
373
373
let res = f. to_host ( ) . powi ( i) . to_soft ( ) ;
374
374
@@ -528,8 +528,8 @@ fn random_nan<S: Semantics>(rng: &mut StdRng) -> IeeeFloat<S> {
528
528
/// and the C standard leaves behavior for SNaNs unspecified.
529
529
///
530
530
/// 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 < ' _ > ,
533
533
intrinsic_name : & str ,
534
534
args : & [ IeeeFloat < S > ] ,
535
535
) -> Option < IeeeFloat < S > > {
@@ -550,6 +550,7 @@ fn fixed_float_value<'tcx, S: Semantics>(
550
550
// Handle both the musl and glibc cases non-deterministically.
551
551
if !exp. is_signaling ( ) || rng. random ( ) { one } else { random_nan ( rng) }
552
552
}
553
+
553
554
// x^(±0) = 1 for any x, even a NaN, *but* not a SNaN
554
555
( "powf32" | "powf64" , [ base, exp] ) if exp. is_zero ( ) => {
555
556
// Handle both the musl and glibc cases non-deterministically.
@@ -569,13 +570,21 @@ fn fixed_float_value<'tcx, S: Semantics>(
569
570
570
571
/// Returns `Some(output)` if `powi` (called `pown` in C) results in a fixed value specified in the C standard
571
572
/// (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
+ }
579
588
580
589
_ => None ,
581
590
}
0 commit comments