@@ -167,6 +167,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
167
167
// This is a "bitwise" operation, so there's no NaN non-determinism.
168
168
this. write_scalar ( Scalar :: from_f64 ( f. abs ( ) ) , dest) ?;
169
169
}
170
+
170
171
"floorf32" | "ceilf32" | "truncf32" | "roundf32" | "rintf32" => {
171
172
let [ f] = check_arg_count ( args) ?;
172
173
let f = this. read_scalar ( f) ?. to_f32 ( ) ?;
@@ -182,6 +183,22 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
182
183
let res = this. adjust_nan ( res, & [ f] ) ;
183
184
this. write_scalar ( res, dest) ?;
184
185
}
186
+ "floorf64" | "ceilf64" | "truncf64" | "roundf64" | "rintf64" => {
187
+ let [ f] = check_arg_count ( args) ?;
188
+ let f = this. read_scalar ( f) ?. to_f64 ( ) ?;
189
+ let mode = match intrinsic_name {
190
+ "floorf64" => Round :: TowardNegative ,
191
+ "ceilf64" => Round :: TowardPositive ,
192
+ "truncf64" => Round :: TowardZero ,
193
+ "roundf64" => Round :: NearestTiesToAway ,
194
+ "rintf64" => Round :: NearestTiesToEven ,
195
+ _ => bug ! ( ) ,
196
+ } ;
197
+ let res = f. round_to_integral ( mode) . value ;
198
+ let res = this. adjust_nan ( res, & [ f] ) ;
199
+ this. write_scalar ( res, dest) ?;
200
+ }
201
+
185
202
#[ rustfmt:: skip]
186
203
| "sinf32"
187
204
| "cosf32"
@@ -211,22 +228,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
211
228
let res = this. adjust_nan ( res, & [ f] ) ;
212
229
this. write_scalar ( res, dest) ?;
213
230
}
214
-
215
- "floorf64" | "ceilf64" | "truncf64" | "roundf64" | "rintf64" => {
216
- let [ f] = check_arg_count ( args) ?;
217
- let f = this. read_scalar ( f) ?. to_f64 ( ) ?;
218
- let mode = match intrinsic_name {
219
- "floorf64" => Round :: TowardNegative ,
220
- "ceilf64" => Round :: TowardPositive ,
221
- "truncf64" => Round :: TowardZero ,
222
- "roundf64" => Round :: NearestTiesToAway ,
223
- "rintf64" => Round :: NearestTiesToEven ,
224
- _ => bug ! ( ) ,
225
- } ;
226
- let res = f. round_to_integral ( mode) . value ;
227
- let res = this. adjust_nan ( res, & [ f] ) ;
228
- this. write_scalar ( res, dest) ?;
229
- }
230
231
#[ rustfmt:: skip]
231
232
| "sinf64"
232
233
| "cosf64"
@@ -256,84 +257,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
256
257
let res = this. adjust_nan ( res, & [ f] ) ;
257
258
this. write_scalar ( res, dest) ?;
258
259
}
259
- #[ rustfmt:: skip]
260
- | "fadd_algebraic"
261
- | "fsub_algebraic"
262
- | "fmul_algebraic"
263
- | "fdiv_algebraic"
264
- | "frem_algebraic"
265
- => {
266
- let [ a, b] = check_arg_count ( args) ?;
267
- let a = this. read_immediate ( a) ?;
268
- let b = this. read_immediate ( b) ?;
269
- let op = match intrinsic_name {
270
- "fadd_algebraic" => mir:: BinOp :: Add ,
271
- "fsub_algebraic" => mir:: BinOp :: Sub ,
272
- "fmul_algebraic" => mir:: BinOp :: Mul ,
273
- "fdiv_algebraic" => mir:: BinOp :: Div ,
274
- "frem_algebraic" => mir:: BinOp :: Rem ,
275
- _ => bug ! ( ) ,
276
- } ;
277
- let res = this. wrapping_binary_op ( op, & a, & b) ?;
278
- // `wrapping_binary_op` already called `generate_nan` if necessary.
279
- this. write_immediate ( * res, dest) ?;
280
- }
281
-
282
- #[ rustfmt:: skip]
283
- | "fadd_fast"
284
- | "fsub_fast"
285
- | "fmul_fast"
286
- | "fdiv_fast"
287
- | "frem_fast"
288
- => {
289
- let [ a, b] = check_arg_count ( args) ?;
290
- let a = this. read_immediate ( a) ?;
291
- let b = this. read_immediate ( b) ?;
292
- let op = match intrinsic_name {
293
- "fadd_fast" => mir:: BinOp :: Add ,
294
- "fsub_fast" => mir:: BinOp :: Sub ,
295
- "fmul_fast" => mir:: BinOp :: Mul ,
296
- "fdiv_fast" => mir:: BinOp :: Div ,
297
- "frem_fast" => mir:: BinOp :: Rem ,
298
- _ => bug ! ( ) ,
299
- } ;
300
- let float_finite = |x : & ImmTy < ' tcx , _ > | -> InterpResult < ' tcx , bool > {
301
- let ty:: Float ( fty) = x. layout . ty . kind ( ) else {
302
- bug ! ( "float_finite: non-float input type {}" , x. layout. ty)
303
- } ;
304
- Ok ( match fty {
305
- FloatTy :: F16 => unimplemented ! ( "f16_f128" ) ,
306
- FloatTy :: F32 => x. to_scalar ( ) . to_f32 ( ) ?. is_finite ( ) ,
307
- FloatTy :: F64 => x. to_scalar ( ) . to_f64 ( ) ?. is_finite ( ) ,
308
- FloatTy :: F128 => unimplemented ! ( "f16_f128" ) ,
309
- } )
310
- } ;
311
- match ( float_finite ( & a) ?, float_finite ( & b) ?) {
312
- ( false , false ) => throw_ub_format ! (
313
- "`{intrinsic_name}` intrinsic called with non-finite value as both parameters" ,
314
- ) ,
315
- ( false , _) => throw_ub_format ! (
316
- "`{intrinsic_name}` intrinsic called with non-finite value as first parameter" ,
317
- ) ,
318
- ( _, false ) => throw_ub_format ! (
319
- "`{intrinsic_name}` intrinsic called with non-finite value as second parameter" ,
320
- ) ,
321
- _ => { }
322
- }
323
- let res = this. wrapping_binary_op ( op, & a, & b) ?;
324
- if !float_finite ( & res) ? {
325
- throw_ub_format ! ( "`{intrinsic_name}` intrinsic produced non-finite value as result" ) ;
326
- }
327
- // This cannot be a NaN so we also don't have to apply any non-determinism.
328
- // (Also, `wrapping_binary_op` already called `generate_nan` if needed.)
329
- this. write_immediate ( * res, dest) ?;
330
- }
331
260
332
- #[ rustfmt:: skip]
333
- | "minnumf32"
334
- | "maxnumf32"
335
- | "copysignf32"
336
- => {
261
+ "minnumf32" | "maxnumf32" | "copysignf32" => {
337
262
let [ a, b] = check_arg_count ( args) ?;
338
263
let a = this. read_scalar ( a) ?. to_f32 ( ) ?;
339
264
let b = this. read_scalar ( b) ?. to_f32 ( ) ?;
@@ -345,12 +270,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
345
270
} ;
346
271
this. write_scalar ( Scalar :: from_f32 ( res) , dest) ?;
347
272
}
348
-
349
- #[ rustfmt:: skip]
350
- | "minnumf64"
351
- | "maxnumf64"
352
- | "copysignf64"
353
- => {
273
+ "minnumf64" | "maxnumf64" | "copysignf64" => {
354
274
let [ a, b] = check_arg_count ( args) ?;
355
275
let a = this. read_scalar ( a) ?. to_f64 ( ) ?;
356
276
let b = this. read_scalar ( b) ?. to_f64 ( ) ?;
@@ -373,7 +293,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
373
293
let res = this. adjust_nan ( res, & [ a, b, c] ) ;
374
294
this. write_scalar ( res, dest) ?;
375
295
}
376
-
377
296
"fmaf64" => {
378
297
let [ a, b, c] = check_arg_count ( args) ?;
379
298
let a = this. read_scalar ( a) ?. to_f64 ( ) ?;
@@ -394,7 +313,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
394
313
let res = this. adjust_nan ( res, & [ f1, f2] ) ;
395
314
this. write_scalar ( res, dest) ?;
396
315
}
397
-
398
316
"powf64" => {
399
317
let [ f1, f2] = check_arg_count ( args) ?;
400
318
let f1 = this. read_scalar ( f1) ?. to_f64 ( ) ?;
@@ -414,7 +332,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
414
332
let res = this. adjust_nan ( res, & [ f] ) ;
415
333
this. write_scalar ( res, dest) ?;
416
334
}
417
-
418
335
"powif64" => {
419
336
let [ f, i] = check_arg_count ( args) ?;
420
337
let f = this. read_scalar ( f) ?. to_f64 ( ) ?;
@@ -425,6 +342,79 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
425
342
this. write_scalar ( res, dest) ?;
426
343
}
427
344
345
+ #[ rustfmt:: skip]
346
+ | "fadd_algebraic"
347
+ | "fsub_algebraic"
348
+ | "fmul_algebraic"
349
+ | "fdiv_algebraic"
350
+ | "frem_algebraic"
351
+ => {
352
+ let [ a, b] = check_arg_count ( args) ?;
353
+ let a = this. read_immediate ( a) ?;
354
+ let b = this. read_immediate ( b) ?;
355
+ let op = match intrinsic_name {
356
+ "fadd_algebraic" => mir:: BinOp :: Add ,
357
+ "fsub_algebraic" => mir:: BinOp :: Sub ,
358
+ "fmul_algebraic" => mir:: BinOp :: Mul ,
359
+ "fdiv_algebraic" => mir:: BinOp :: Div ,
360
+ "frem_algebraic" => mir:: BinOp :: Rem ,
361
+ _ => bug ! ( ) ,
362
+ } ;
363
+ let res = this. wrapping_binary_op ( op, & a, & b) ?;
364
+ // `wrapping_binary_op` already called `generate_nan` if necessary.
365
+ this. write_immediate ( * res, dest) ?;
366
+ }
367
+
368
+ #[ rustfmt:: skip]
369
+ | "fadd_fast"
370
+ | "fsub_fast"
371
+ | "fmul_fast"
372
+ | "fdiv_fast"
373
+ | "frem_fast"
374
+ => {
375
+ let [ a, b] = check_arg_count ( args) ?;
376
+ let a = this. read_immediate ( a) ?;
377
+ let b = this. read_immediate ( b) ?;
378
+ let op = match intrinsic_name {
379
+ "fadd_fast" => mir:: BinOp :: Add ,
380
+ "fsub_fast" => mir:: BinOp :: Sub ,
381
+ "fmul_fast" => mir:: BinOp :: Mul ,
382
+ "fdiv_fast" => mir:: BinOp :: Div ,
383
+ "frem_fast" => mir:: BinOp :: Rem ,
384
+ _ => bug ! ( ) ,
385
+ } ;
386
+ let float_finite = |x : & ImmTy < ' tcx , _ > | -> InterpResult < ' tcx , bool > {
387
+ let ty:: Float ( fty) = x. layout . ty . kind ( ) else {
388
+ bug ! ( "float_finite: non-float input type {}" , x. layout. ty)
389
+ } ;
390
+ Ok ( match fty {
391
+ FloatTy :: F16 => unimplemented ! ( "f16_f128" ) ,
392
+ FloatTy :: F32 => x. to_scalar ( ) . to_f32 ( ) ?. is_finite ( ) ,
393
+ FloatTy :: F64 => x. to_scalar ( ) . to_f64 ( ) ?. is_finite ( ) ,
394
+ FloatTy :: F128 => unimplemented ! ( "f16_f128" ) ,
395
+ } )
396
+ } ;
397
+ match ( float_finite ( & a) ?, float_finite ( & b) ?) {
398
+ ( false , false ) => throw_ub_format ! (
399
+ "`{intrinsic_name}` intrinsic called with non-finite value as both parameters" ,
400
+ ) ,
401
+ ( false , _) => throw_ub_format ! (
402
+ "`{intrinsic_name}` intrinsic called with non-finite value as first parameter" ,
403
+ ) ,
404
+ ( _, false ) => throw_ub_format ! (
405
+ "`{intrinsic_name}` intrinsic called with non-finite value as second parameter" ,
406
+ ) ,
407
+ _ => { }
408
+ }
409
+ let res = this. wrapping_binary_op ( op, & a, & b) ?;
410
+ if !float_finite ( & res) ? {
411
+ throw_ub_format ! ( "`{intrinsic_name}` intrinsic produced non-finite value as result" ) ;
412
+ }
413
+ // This cannot be a NaN so we also don't have to apply any non-determinism.
414
+ // (Also, `wrapping_binary_op` already called `generate_nan` if needed.)
415
+ this. write_immediate ( * res, dest) ?;
416
+ }
417
+
428
418
"float_to_int_unchecked" => {
429
419
let [ val] = check_arg_count ( args) ?;
430
420
let val = this. read_immediate ( val) ?;
0 commit comments