@@ -371,7 +371,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
371
371
| "simd_lt"
372
372
| "simd_le"
373
373
| "simd_gt"
374
- | "simd_ge" => {
374
+ | "simd_ge"
375
+ | "simd_fmax"
376
+ | "simd_fmin" => {
375
377
use mir:: BinOp ;
376
378
377
379
let & [ ref left, ref right] = check_arg_count ( args) ?;
@@ -382,50 +384,69 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
382
384
assert_eq ! ( dest_len, left_len) ;
383
385
assert_eq ! ( dest_len, right_len) ;
384
386
385
- let mir_op = match intrinsic_name {
386
- "simd_add" => BinOp :: Add ,
387
- "simd_sub" => BinOp :: Sub ,
388
- "simd_mul" => BinOp :: Mul ,
389
- "simd_div" => BinOp :: Div ,
390
- "simd_rem" => BinOp :: Rem ,
391
- "simd_shl" => BinOp :: Shl ,
392
- "simd_shr" => BinOp :: Shr ,
393
- "simd_and" => BinOp :: BitAnd ,
394
- "simd_or" => BinOp :: BitOr ,
395
- "simd_xor" => BinOp :: BitXor ,
396
- "simd_eq" => BinOp :: Eq ,
397
- "simd_ne" => BinOp :: Ne ,
398
- "simd_lt" => BinOp :: Lt ,
399
- "simd_le" => BinOp :: Le ,
400
- "simd_gt" => BinOp :: Gt ,
401
- "simd_ge" => BinOp :: Ge ,
387
+ enum Op {
388
+ MirOp ( BinOp ) ,
389
+ FMax ,
390
+ FMin ,
391
+ }
392
+ let which = match intrinsic_name {
393
+ "simd_add" => Op :: MirOp ( BinOp :: Add ) ,
394
+ "simd_sub" => Op :: MirOp ( BinOp :: Sub ) ,
395
+ "simd_mul" => Op :: MirOp ( BinOp :: Mul ) ,
396
+ "simd_div" => Op :: MirOp ( BinOp :: Div ) ,
397
+ "simd_rem" => Op :: MirOp ( BinOp :: Rem ) ,
398
+ "simd_shl" => Op :: MirOp ( BinOp :: Shl ) ,
399
+ "simd_shr" => Op :: MirOp ( BinOp :: Shr ) ,
400
+ "simd_and" => Op :: MirOp ( BinOp :: BitAnd ) ,
401
+ "simd_or" => Op :: MirOp ( BinOp :: BitOr ) ,
402
+ "simd_xor" => Op :: MirOp ( BinOp :: BitXor ) ,
403
+ "simd_eq" => Op :: MirOp ( BinOp :: Eq ) ,
404
+ "simd_ne" => Op :: MirOp ( BinOp :: Ne ) ,
405
+ "simd_lt" => Op :: MirOp ( BinOp :: Lt ) ,
406
+ "simd_le" => Op :: MirOp ( BinOp :: Le ) ,
407
+ "simd_gt" => Op :: MirOp ( BinOp :: Gt ) ,
408
+ "simd_ge" => Op :: MirOp ( BinOp :: Ge ) ,
409
+ "simd_fmax" => Op :: FMax ,
410
+ "simd_fmin" => Op :: FMin ,
402
411
_ => unreachable ! ( ) ,
403
412
} ;
404
413
405
414
for i in 0 ..dest_len {
406
415
let left = this. read_immediate ( & this. mplace_index ( & left, i) ?. into ( ) ) ?;
407
416
let right = this. read_immediate ( & this. mplace_index ( & right, i) ?. into ( ) ) ?;
408
417
let dest = this. mplace_index ( & dest, i) ?;
409
- let ( val, overflowed, ty) = this. overflowing_binary_op ( mir_op, & left, & right) ?;
410
- if matches ! ( mir_op, BinOp :: Shl | BinOp :: Shr ) {
411
- // Shifts have extra UB as SIMD operations that the MIR binop does not have.
412
- // See <https://github.com/rust-lang/rust/issues/91237>.
413
- if overflowed {
414
- let r_val = right. to_scalar ( ) ?. to_bits ( right. layout . size ) ?;
415
- throw_ub_format ! ( "overflowing shift by {} in `{}` in SIMD lane {}" , r_val, intrinsic_name, i) ;
418
+ let val = match which {
419
+ Op :: MirOp ( mir_op) => {
420
+ let ( val, overflowed, ty) = this. overflowing_binary_op ( mir_op, & left, & right) ?;
421
+ if matches ! ( mir_op, BinOp :: Shl | BinOp :: Shr ) {
422
+ // Shifts have extra UB as SIMD operations that the MIR binop does not have.
423
+ // See <https://github.com/rust-lang/rust/issues/91237>.
424
+ if overflowed {
425
+ let r_val = right. to_scalar ( ) ?. to_bits ( right. layout . size ) ?;
426
+ throw_ub_format ! ( "overflowing shift by {} in `{}` in SIMD lane {}" , r_val, intrinsic_name, i) ;
427
+ }
428
+ }
429
+ if matches ! ( mir_op, BinOp :: Eq | BinOp :: Ne | BinOp :: Lt | BinOp :: Le | BinOp :: Gt | BinOp :: Ge ) {
430
+ // Special handling for boolean-returning operations
431
+ assert_eq ! ( ty, this. tcx. types. bool ) ;
432
+ let val = val. to_bool ( ) . unwrap ( ) ;
433
+ bool_to_simd_element ( val, dest. layout . size )
434
+ } else {
435
+ assert_ne ! ( ty, this. tcx. types. bool ) ;
436
+ assert_eq ! ( ty, dest. layout. ty) ;
437
+ val
438
+ }
439
+ }
440
+ Op :: FMax => {
441
+ assert ! ( matches!( dest. layout. ty. kind( ) , ty:: Float ( _) ) ) ;
442
+ this. max_op ( & left, & right) ?. to_scalar ( ) ?
416
443
}
417
- }
418
- if matches ! ( mir_op, BinOp :: Eq | BinOp :: Ne | BinOp :: Lt | BinOp :: Le | BinOp :: Gt | BinOp :: Ge ) {
419
- // Special handling for boolean-returning operations
420
- assert_eq ! ( ty, this. tcx. types. bool ) ;
421
- let val = val. to_bool ( ) . unwrap ( ) ;
422
- let val = bool_to_simd_element ( val, dest. layout . size ) ;
423
- this. write_scalar ( val, & dest. into ( ) ) ?;
424
- } else {
425
- assert_ne ! ( ty, this. tcx. types. bool ) ;
426
- assert_eq ! ( ty, dest. layout. ty) ;
427
- this. write_scalar ( val, & dest. into ( ) ) ?;
428
- }
444
+ Op :: FMin => {
445
+ assert ! ( matches!( dest. layout. ty. kind( ) , ty:: Float ( _) ) ) ;
446
+ this. min_op ( & left, & right) ?. to_scalar ( ) ?
447
+ }
448
+ } ;
449
+ this. write_scalar ( val, & dest. into ( ) ) ?;
429
450
}
430
451
}
431
452
#[ rustfmt:: skip]
@@ -478,24 +499,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
478
499
this. binary_op ( mir_op, & res, & op) ?
479
500
}
480
501
Op :: Max => {
481
- // if `op > res`...
482
- if this. binary_op ( BinOp :: Gt , & op, & res) ?. to_scalar ( ) ?. to_bool ( ) ? {
483
- // update accumulator
484
- op
485
- } else {
486
- // no change
487
- res
488
- }
502
+ this. max_op ( & res, & op) ?
489
503
}
490
504
Op :: Min => {
491
- // if `op < res`...
492
- if this. binary_op ( BinOp :: Lt , & op, & res) ?. to_scalar ( ) ?. to_bool ( ) ? {
493
- // update accumulator
494
- op
495
- } else {
496
- // no change
497
- res
498
- }
505
+ this. min_op ( & res, & op) ?
499
506
}
500
507
} ;
501
508
}
@@ -1071,4 +1078,30 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
1071
1078
_ => bug ! ( "`float_to_int_unchecked` called with non-int output type {:?}" , dest_ty) ,
1072
1079
} )
1073
1080
}
1081
+
1082
+ fn max_op (
1083
+ & self ,
1084
+ left : & ImmTy < ' tcx , Tag > ,
1085
+ right : & ImmTy < ' tcx , Tag > ,
1086
+ ) -> InterpResult < ' tcx , ImmTy < ' tcx , Tag > > {
1087
+ let this = self . eval_context_ref ( ) ;
1088
+ Ok ( if this. binary_op ( BinOp :: Gt , left, right) ?. to_scalar ( ) ?. to_bool ( ) ? {
1089
+ * left
1090
+ } else {
1091
+ * right
1092
+ } )
1093
+ }
1094
+
1095
+ fn min_op (
1096
+ & self ,
1097
+ left : & ImmTy < ' tcx , Tag > ,
1098
+ right : & ImmTy < ' tcx , Tag > ,
1099
+ ) -> InterpResult < ' tcx , ImmTy < ' tcx , Tag > > {
1100
+ let this = self . eval_context_ref ( ) ;
1101
+ Ok ( if this. binary_op ( BinOp :: Lt , left, right) ?. to_scalar ( ) ?. to_bool ( ) ? {
1102
+ * left
1103
+ } else {
1104
+ * right
1105
+ } )
1106
+ }
1074
1107
}
0 commit comments