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