1+ use  std:: convert:: TryInto ; 
2+ 
3+ use  rustc_apfloat:: Float ; 
14use  rustc:: ty:: layout:: { Align ,  LayoutOf ,  Size } ; 
25use  rustc:: hir:: def_id:: DefId ; 
36use  rustc:: mir; 
@@ -577,7 +580,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
577580                } ; 
578581                this. write_scalar ( Scalar :: from_u64 ( f. to_bits ( ) ) ,  dest) ?; 
579582            } 
580-             // underscore case for windows 
583+             // underscore case for windows, here and below 
584+             // (see https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/floating-point-primitives?view=vs-2019) 
581585            "_hypot"  | "hypot"  | "atan2"  => { 
582586                // FIXME: Using host floats. 
583587                let  f1 = f64:: from_bits ( this. read_scalar ( args[ 0 ] ) ?. to_u64 ( ) ?) ; 
@@ -589,16 +593,23 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
589593                } ; 
590594                this. write_scalar ( Scalar :: from_u64 ( n. to_bits ( ) ) ,  dest) ?; 
591595            } 
592-             // underscore case for windows 
593-             "_ldexp"  | "ldexp"  => { 
594-                 // FIXME: Using host floats. 
595-                 let  x = f64:: from_bits ( this. read_scalar ( args[ 0 ] ) ?. to_u64 ( ) ?) ; 
596+             // For radix-2 (binary) systems, `ldexp` and `scalbn` are the same. 
597+             "_ldexp"  | "ldexp"  | "scalbn"  => { 
598+                 let  x = this. read_scalar ( args[ 0 ] ) ?. to_f64 ( ) ?; 
596599                let  exp = this. read_scalar ( args[ 1 ] ) ?. to_i32 ( ) ?; 
597-                 extern  { 
598-                     fn  ldexp ( x :  f64 ,  n :  i32 )  -> f64 ; 
599-                 } 
600-                 let  n = unsafe  {  ldexp ( x,  exp)  } ; 
601-                 this. write_scalar ( Scalar :: from_u64 ( n. to_bits ( ) ) ,  dest) ?; 
600+ 
601+                 // Saturating cast to i16. Even those are outside the valid exponent range to 
602+                 // `scalbn` below will do its over/underflow handling. 
603+                 let  exp = if  exp > i16:: max_value ( )  as  i32  { 
604+                     i16:: max_value ( ) 
605+                 }  else  if  exp < i16:: min_value ( )  as  i32  { 
606+                     i16:: min_value ( ) 
607+                 }  else  { 
608+                     exp. try_into ( ) . unwrap ( ) 
609+                 } ; 
610+ 
611+                 let  res = x. scalbn ( exp) ; 
612+                 this. write_scalar ( Scalar :: from_f64 ( res) ,  dest) ?; 
602613            } 
603614
604615            // Some things needed for `sys::thread` initialization to go through. 
0 commit comments