@@ -15,7 +15,7 @@ use rustc_target::abi::Size;
1515
1616use crate :: * ;
1717use atomic:: EvalContextExt as _;
18- use helpers:: check_arg_count;
18+ use helpers:: { check_arg_count, ToHost , ToSoft } ;
1919use simd:: EvalContextExt as _;
2020
2121impl < ' mir , ' tcx : ' mir > EvalContextExt < ' mir , ' tcx > for crate :: MiriInterpCx < ' mir , ' tcx > { }
@@ -146,12 +146,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
146146 let [ f] = check_arg_count ( args) ?;
147147 let f = this. read_scalar ( f) ?. to_f32 ( ) ?;
148148 // Can be implemented in soft-floats.
149+ // This is a "bitwise" operation, so there's no NaN non-determinism.
149150 this. write_scalar ( Scalar :: from_f32 ( f. abs ( ) ) , dest) ?;
150151 }
151152 "fabsf64" => {
152153 let [ f] = check_arg_count ( args) ?;
153154 let f = this. read_scalar ( f) ?. to_f64 ( ) ?;
154155 // Can be implemented in soft-floats.
156+ // This is a "bitwise" operation, so there's no NaN non-determinism.
155157 this. write_scalar ( Scalar :: from_f64 ( f. abs ( ) ) , dest) ?;
156158 }
157159 #[ rustfmt:: skip]
@@ -170,25 +172,28 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
170172 | "rintf32"
171173 => {
172174 let [ f] = check_arg_count ( args) ?;
175+ let f = this. read_scalar ( f) ?. to_f32 ( ) ?;
173176 // FIXME: Using host floats.
174- let f = f32 :: from_bits ( this . read_scalar ( f ) ? . to_u32 ( ) ? ) ;
175- let f = match intrinsic_name {
176- "sinf32" => f . sin ( ) ,
177- "cosf32" => f . cos ( ) ,
178- "sqrtf32" => f . sqrt ( ) ,
179- "expf32" => f . exp ( ) ,
180- "exp2f32" => f . exp2 ( ) ,
181- "logf32" => f . ln ( ) ,
182- "log10f32" => f . log10 ( ) ,
183- "log2f32" => f . log2 ( ) ,
184- "floorf32" => f . floor ( ) ,
185- "ceilf32" => f . ceil ( ) ,
186- "truncf32" => f . trunc ( ) ,
187- "roundf32" => f . round ( ) ,
188- "rintf32" => f . round_ties_even ( ) ,
177+ let f_host = f . to_host ( ) ;
178+ let res = match intrinsic_name {
179+ "sinf32" => f_host . sin ( ) ,
180+ "cosf32" => f_host . cos ( ) ,
181+ "sqrtf32" => f_host . sqrt ( ) ,
182+ "expf32" => f_host . exp ( ) ,
183+ "exp2f32" => f_host . exp2 ( ) ,
184+ "logf32" => f_host . ln ( ) ,
185+ "log10f32" => f_host . log10 ( ) ,
186+ "log2f32" => f_host . log2 ( ) ,
187+ "floorf32" => f_host . floor ( ) ,
188+ "ceilf32" => f_host . ceil ( ) ,
189+ "truncf32" => f_host . trunc ( ) ,
190+ "roundf32" => f_host . round ( ) ,
191+ "rintf32" => f_host . round_ties_even ( ) ,
189192 _ => bug ! ( ) ,
190193 } ;
191- this. write_scalar ( Scalar :: from_u32 ( f. to_bits ( ) ) , dest) ?;
194+ let res = res. to_soft ( ) ;
195+ let res = this. adjust_nan ( res, & [ f] ) ;
196+ this. write_scalar ( res, dest) ?;
192197 }
193198
194199 #[ rustfmt:: skip]
@@ -207,25 +212,28 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
207212 | "rintf64"
208213 => {
209214 let [ f] = check_arg_count ( args) ?;
215+ let f = this. read_scalar ( f) ?. to_f64 ( ) ?;
210216 // FIXME: Using host floats.
211- let f = f64 :: from_bits ( this . read_scalar ( f ) ? . to_u64 ( ) ? ) ;
212- let f = match intrinsic_name {
213- "sinf64" => f . sin ( ) ,
214- "cosf64" => f . cos ( ) ,
215- "sqrtf64" => f . sqrt ( ) ,
216- "expf64" => f . exp ( ) ,
217- "exp2f64" => f . exp2 ( ) ,
218- "logf64" => f . ln ( ) ,
219- "log10f64" => f . log10 ( ) ,
220- "log2f64" => f . log2 ( ) ,
221- "floorf64" => f . floor ( ) ,
222- "ceilf64" => f . ceil ( ) ,
223- "truncf64" => f . trunc ( ) ,
224- "roundf64" => f . round ( ) ,
225- "rintf64" => f . round_ties_even ( ) ,
217+ let f_host = f . to_host ( ) ;
218+ let res = match intrinsic_name {
219+ "sinf64" => f_host . sin ( ) ,
220+ "cosf64" => f_host . cos ( ) ,
221+ "sqrtf64" => f_host . sqrt ( ) ,
222+ "expf64" => f_host . exp ( ) ,
223+ "exp2f64" => f_host . exp2 ( ) ,
224+ "logf64" => f_host . ln ( ) ,
225+ "log10f64" => f_host . log10 ( ) ,
226+ "log2f64" => f_host . log2 ( ) ,
227+ "floorf64" => f_host . floor ( ) ,
228+ "ceilf64" => f_host . ceil ( ) ,
229+ "truncf64" => f_host . trunc ( ) ,
230+ "roundf64" => f_host . round ( ) ,
231+ "rintf64" => f_host . round_ties_even ( ) ,
226232 _ => bug ! ( ) ,
227233 } ;
228- this. write_scalar ( Scalar :: from_u64 ( f. to_bits ( ) ) , dest) ?;
234+ let res = res. to_soft ( ) ;
235+ let res = this. adjust_nan ( res, & [ f] ) ;
236+ this. write_scalar ( res, dest) ?;
229237 }
230238
231239 #[ rustfmt:: skip]
@@ -272,6 +280,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
272280 if !float_finite ( & res) ? {
273281 throw_ub_format ! ( "`{intrinsic_name}` intrinsic produced non-finite value as result" ) ;
274282 }
283+ // This cannot be a NaN so we also don't have to apply any non-determinism.
284+ // (Also, `wrapping_binary_op` already called `generate_nan` if needed.)
275285 this. write_immediate ( * res, dest) ?;
276286 }
277287
@@ -284,9 +294,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
284294 let a = this. read_scalar ( a) ?. to_f32 ( ) ?;
285295 let b = this. read_scalar ( b) ?. to_f32 ( ) ?;
286296 let res = match intrinsic_name {
287- "minnumf32" => a. min ( b) ,
288- "maxnumf32" => a. max ( b) ,
289- "copysignf32" => a. copy_sign ( b) ,
297+ "minnumf32" => this . adjust_nan ( a. min ( b) , & [ a , b ] ) ,
298+ "maxnumf32" => this . adjust_nan ( a. max ( b) , & [ a , b ] ) ,
299+ "copysignf32" => a. copy_sign ( b) , // bitwise, no NaN adjustments
290300 _ => bug ! ( ) ,
291301 } ;
292302 this. write_scalar ( Scalar :: from_f32 ( res) , dest) ?;
@@ -301,68 +311,74 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
301311 let a = this. read_scalar ( a) ?. to_f64 ( ) ?;
302312 let b = this. read_scalar ( b) ?. to_f64 ( ) ?;
303313 let res = match intrinsic_name {
304- "minnumf64" => a. min ( b) ,
305- "maxnumf64" => a. max ( b) ,
306- "copysignf64" => a. copy_sign ( b) ,
314+ "minnumf64" => this . adjust_nan ( a. min ( b) , & [ a , b ] ) ,
315+ "maxnumf64" => this . adjust_nan ( a. max ( b) , & [ a , b ] ) ,
316+ "copysignf64" => a. copy_sign ( b) , // bitwise, no NaN adjustments
307317 _ => bug ! ( ) ,
308318 } ;
309319 this. write_scalar ( Scalar :: from_f64 ( res) , dest) ?;
310320 }
311321
312- "powf32" => {
313- let [ f, f2] = check_arg_count ( args) ?;
314- // FIXME: Using host floats.
315- let f = f32:: from_bits ( this. read_scalar ( f) ?. to_u32 ( ) ?) ;
316- let f2 = f32:: from_bits ( this. read_scalar ( f2) ?. to_u32 ( ) ?) ;
317- let res = f. powf ( f2) ;
318- this. write_scalar ( Scalar :: from_u32 ( res. to_bits ( ) ) , dest) ?;
319- }
320-
321- "powf64" => {
322- let [ f, f2] = check_arg_count ( args) ?;
323- // FIXME: Using host floats.
324- let f = f64:: from_bits ( this. read_scalar ( f) ?. to_u64 ( ) ?) ;
325- let f2 = f64:: from_bits ( this. read_scalar ( f2) ?. to_u64 ( ) ?) ;
326- let res = f. powf ( f2) ;
327- this. write_scalar ( Scalar :: from_u64 ( res. to_bits ( ) ) , dest) ?;
328- }
329-
330322 "fmaf32" => {
331323 let [ a, b, c] = check_arg_count ( args) ?;
324+ let a = this. read_scalar ( a) ?. to_f32 ( ) ?;
325+ let b = this. read_scalar ( b) ?. to_f32 ( ) ?;
326+ let c = this. read_scalar ( c) ?. to_f32 ( ) ?;
332327 // FIXME: Using host floats, to work around https://github.com/rust-lang/rustc_apfloat/issues/11
333- let a = f32:: from_bits ( this. read_scalar ( a) ?. to_u32 ( ) ?) ;
334- let b = f32:: from_bits ( this. read_scalar ( b) ?. to_u32 ( ) ?) ;
335- let c = f32:: from_bits ( this. read_scalar ( c) ?. to_u32 ( ) ?) ;
336- let res = a. mul_add ( b, c) ;
337- this. write_scalar ( Scalar :: from_u32 ( res. to_bits ( ) ) , dest) ?;
328+ let res = a. to_host ( ) . mul_add ( b. to_host ( ) , c. to_host ( ) ) . to_soft ( ) ;
329+ let res = this. adjust_nan ( res, & [ a, b, c] ) ;
330+ this. write_scalar ( res, dest) ?;
338331 }
339332
340333 "fmaf64" => {
341334 let [ a, b, c] = check_arg_count ( args) ?;
335+ let a = this. read_scalar ( a) ?. to_f64 ( ) ?;
336+ let b = this. read_scalar ( b) ?. to_f64 ( ) ?;
337+ let c = this. read_scalar ( c) ?. to_f64 ( ) ?;
342338 // FIXME: Using host floats, to work around https://github.com/rust-lang/rustc_apfloat/issues/11
343- let a = f64:: from_bits ( this. read_scalar ( a) ?. to_u64 ( ) ?) ;
344- let b = f64:: from_bits ( this. read_scalar ( b) ?. to_u64 ( ) ?) ;
345- let c = f64:: from_bits ( this. read_scalar ( c) ?. to_u64 ( ) ?) ;
346- let res = a. mul_add ( b, c) ;
347- this. write_scalar ( Scalar :: from_u64 ( res. to_bits ( ) ) , dest) ?;
339+ let res = a. to_host ( ) . mul_add ( b. to_host ( ) , c. to_host ( ) ) . to_soft ( ) ;
340+ let res = this. adjust_nan ( res, & [ a, b, c] ) ;
341+ this. write_scalar ( res, dest) ?;
342+ }
343+
344+ "powf32" => {
345+ let [ f1, f2] = check_arg_count ( args) ?;
346+ let f1 = this. read_scalar ( f1) ?. to_f32 ( ) ?;
347+ let f2 = this. read_scalar ( f2) ?. to_f32 ( ) ?;
348+ // FIXME: Using host floats.
349+ let res = f1. to_host ( ) . powf ( f2. to_host ( ) ) . to_soft ( ) ;
350+ let res = this. adjust_nan ( res, & [ f1, f2] ) ;
351+ this. write_scalar ( res, dest) ?;
352+ }
353+
354+ "powf64" => {
355+ let [ f1, f2] = check_arg_count ( args) ?;
356+ let f1 = this. read_scalar ( f1) ?. to_f64 ( ) ?;
357+ let f2 = this. read_scalar ( f2) ?. to_f64 ( ) ?;
358+ // FIXME: Using host floats.
359+ let res = f1. to_host ( ) . powf ( f2. to_host ( ) ) . to_soft ( ) ;
360+ let res = this. adjust_nan ( res, & [ f1, f2] ) ;
361+ this. write_scalar ( res, dest) ?;
348362 }
349363
350364 "powif32" => {
351365 let [ f, i] = check_arg_count ( args) ?;
352- // FIXME: Using host floats.
353- let f = f32:: from_bits ( this. read_scalar ( f) ?. to_u32 ( ) ?) ;
366+ let f = this. read_scalar ( f) ?. to_f32 ( ) ?;
354367 let i = this. read_scalar ( i) ?. to_i32 ( ) ?;
355- let res = f. powi ( i) ;
356- this. write_scalar ( Scalar :: from_u32 ( res. to_bits ( ) ) , dest) ?;
368+ // FIXME: Using host floats.
369+ let res = f. to_host ( ) . powi ( i) . to_soft ( ) ;
370+ let res = this. adjust_nan ( res, & [ f] ) ;
371+ this. write_scalar ( res, dest) ?;
357372 }
358373
359374 "powif64" => {
360375 let [ f, i] = check_arg_count ( args) ?;
361- // FIXME: Using host floats.
362- let f = f64:: from_bits ( this. read_scalar ( f) ?. to_u64 ( ) ?) ;
376+ let f = this. read_scalar ( f) ?. to_f64 ( ) ?;
363377 let i = this. read_scalar ( i) ?. to_i32 ( ) ?;
364- let res = f. powi ( i) ;
365- this. write_scalar ( Scalar :: from_u64 ( res. to_bits ( ) ) , dest) ?;
378+ // FIXME: Using host floats.
379+ let res = f. to_host ( ) . powi ( i) . to_soft ( ) ;
380+ let res = this. adjust_nan ( res, & [ f] ) ;
381+ this. write_scalar ( res, dest) ?;
366382 }
367383
368384 "float_to_int_unchecked" => {
0 commit comments