@@ -15,7 +15,7 @@ use rustc_target::abi::Size;
15
15
16
16
use crate :: * ;
17
17
use atomic:: EvalContextExt as _;
18
- use helpers:: check_arg_count;
18
+ use helpers:: { check_arg_count, ToHost , ToSoft } ;
19
19
use simd:: EvalContextExt as _;
20
20
21
21
impl < ' 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> {
146
146
let [ f] = check_arg_count ( args) ?;
147
147
let f = this. read_scalar ( f) ?. to_f32 ( ) ?;
148
148
// Can be implemented in soft-floats.
149
+ // This is a "bitwise" operation, so there's no NaN non-determinism.
149
150
this. write_scalar ( Scalar :: from_f32 ( f. abs ( ) ) , dest) ?;
150
151
}
151
152
"fabsf64" => {
152
153
let [ f] = check_arg_count ( args) ?;
153
154
let f = this. read_scalar ( f) ?. to_f64 ( ) ?;
154
155
// Can be implemented in soft-floats.
156
+ // This is a "bitwise" operation, so there's no NaN non-determinism.
155
157
this. write_scalar ( Scalar :: from_f64 ( f. abs ( ) ) , dest) ?;
156
158
}
157
159
#[ rustfmt:: skip]
@@ -170,25 +172,28 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
170
172
| "rintf32"
171
173
=> {
172
174
let [ f] = check_arg_count ( args) ?;
175
+ let f = this. read_scalar ( f) ?. to_f32 ( ) ?;
173
176
// 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 ( ) ,
189
192
_ => bug ! ( ) ,
190
193
} ;
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) ?;
192
197
}
193
198
194
199
#[ rustfmt:: skip]
@@ -207,25 +212,28 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
207
212
| "rintf64"
208
213
=> {
209
214
let [ f] = check_arg_count ( args) ?;
215
+ let f = this. read_scalar ( f) ?. to_f64 ( ) ?;
210
216
// 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 ( ) ,
226
232
_ => bug ! ( ) ,
227
233
} ;
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) ?;
229
237
}
230
238
231
239
#[ rustfmt:: skip]
@@ -272,6 +280,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
272
280
if !float_finite ( & res) ? {
273
281
throw_ub_format ! ( "`{intrinsic_name}` intrinsic produced non-finite value as result" ) ;
274
282
}
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.)
275
285
this. write_immediate ( * res, dest) ?;
276
286
}
277
287
@@ -284,9 +294,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
284
294
let a = this. read_scalar ( a) ?. to_f32 ( ) ?;
285
295
let b = this. read_scalar ( b) ?. to_f32 ( ) ?;
286
296
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
290
300
_ => bug ! ( ) ,
291
301
} ;
292
302
this. write_scalar ( Scalar :: from_f32 ( res) , dest) ?;
@@ -301,68 +311,74 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
301
311
let a = this. read_scalar ( a) ?. to_f64 ( ) ?;
302
312
let b = this. read_scalar ( b) ?. to_f64 ( ) ?;
303
313
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
307
317
_ => bug ! ( ) ,
308
318
} ;
309
319
this. write_scalar ( Scalar :: from_f64 ( res) , dest) ?;
310
320
}
311
321
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
-
330
322
"fmaf32" => {
331
323
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 ( ) ?;
332
327
// 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) ?;
338
331
}
339
332
340
333
"fmaf64" => {
341
334
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 ( ) ?;
342
338
// 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) ?;
348
362
}
349
363
350
364
"powif32" => {
351
365
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 ( ) ?;
354
367
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) ?;
357
372
}
358
373
359
374
"powif64" => {
360
375
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 ( ) ?;
363
377
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) ?;
366
382
}
367
383
368
384
"float_to_int_unchecked" => {
0 commit comments