@@ -324,12 +324,22 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
324
324
325
325
assert_eq ! ( dest_len, op_len) ;
326
326
327
+ enum Op {
328
+ MirOp ( mir:: UnOp ) ,
329
+ Abs ,
330
+ }
331
+ let which = match intrinsic_name {
332
+ "simd_neg" => Op :: MirOp ( mir:: UnOp :: Neg ) ,
333
+ "simd_fabs" => Op :: Abs ,
334
+ _ => unreachable ! ( ) ,
335
+ } ;
336
+
327
337
for i in 0 ..dest_len {
328
338
let op = this. read_immediate ( & this. mplace_index ( & op, i) ?. into ( ) ) ?;
329
339
let dest = this. mplace_index ( & dest, i) ?;
330
- let val = match intrinsic_name {
331
- "simd_neg" => this. unary_op ( mir :: UnOp :: Neg , & op) ?. to_scalar ( ) ?,
332
- "simd_fabs" => {
340
+ let val = match which {
341
+ Op :: MirOp ( mir_op ) => this. unary_op ( mir_op , & op) ?. to_scalar ( ) ?,
342
+ Op :: Abs => {
333
343
// Works for f32 and f64.
334
344
let ty:: Float ( float_ty) = op. layout . ty . kind ( ) else {
335
345
bug ! ( "simd_fabs operand is not a float" )
@@ -341,7 +351,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
341
351
FloatTy :: F64 => Scalar :: from_f64 ( op. to_f64 ( ) ?. abs ( ) ) ,
342
352
}
343
353
}
344
- _ => bug ! ( ) ,
345
354
} ;
346
355
this. write_scalar ( val, & dest. into ( ) ) ?;
347
356
}
@@ -373,7 +382,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
373
382
assert_eq ! ( dest_len, left_len) ;
374
383
assert_eq ! ( dest_len, right_len) ;
375
384
376
- let op = match intrinsic_name {
385
+ let mir_op = match intrinsic_name {
377
386
"simd_add" => BinOp :: Add ,
378
387
"simd_sub" => BinOp :: Sub ,
379
388
"simd_mul" => BinOp :: Mul ,
@@ -397,16 +406,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
397
406
let left = this. read_immediate ( & this. mplace_index ( & left, i) ?. into ( ) ) ?;
398
407
let right = this. read_immediate ( & this. mplace_index ( & right, i) ?. into ( ) ) ?;
399
408
let dest = this. mplace_index ( & dest, i) ?;
400
- let ( val, overflowed, ty) = this. overflowing_binary_op ( op , & left, & right) ?;
401
- if matches ! ( op , BinOp :: Shl | BinOp :: Shr ) {
409
+ let ( val, overflowed, ty) = this. overflowing_binary_op ( mir_op , & left, & right) ?;
410
+ if matches ! ( mir_op , BinOp :: Shl | BinOp :: Shr ) {
402
411
// Shifts have extra UB as SIMD operations that the MIR binop does not have.
403
412
// See <https://github.com/rust-lang/rust/issues/91237>.
404
413
if overflowed {
405
414
let r_val = right. to_scalar ( ) ?. to_bits ( right. layout . size ) ?;
406
415
throw_ub_format ! ( "overflowing shift by {} in `{}` in SIMD lane {}" , r_val, intrinsic_name, i) ;
407
416
}
408
417
}
409
- if matches ! ( op , BinOp :: Eq | BinOp :: Ne | BinOp :: Lt | BinOp :: Le | BinOp :: Gt | BinOp :: Ge ) {
418
+ if matches ! ( mir_op , BinOp :: Eq | BinOp :: Ne | BinOp :: Lt | BinOp :: Le | BinOp :: Gt | BinOp :: Ge ) {
410
419
// Special handling for boolean-returning operations
411
420
assert_eq ! ( ty, this. tcx. types. bool ) ;
412
421
let val = val. to_bool ( ) . unwrap ( ) ;
@@ -419,28 +428,70 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
419
428
}
420
429
}
421
430
}
422
- "simd_reduce_any" | "simd_reduce_all" => {
431
+ #[ rustfmt:: skip]
432
+ | "simd_reduce_and"
433
+ | "simd_reduce_or"
434
+ | "simd_reduce_xor"
435
+ | "simd_reduce_any"
436
+ | "simd_reduce_all" => {
437
+ use mir:: BinOp ;
438
+
423
439
let & [ ref op] = check_arg_count ( args) ?;
424
440
let ( op, op_len) = this. operand_to_simd ( op) ?;
425
441
426
- // the neutral element
427
- let mut res = match intrinsic_name {
428
- "simd_reduce_any" => false ,
429
- "simd_reduce_all" => true ,
430
- _ => bug ! ( ) ,
442
+ let imm_from_bool =
443
+ |b| ImmTy :: from_scalar ( Scalar :: from_bool ( b) , this. machine . layouts . bool ) ;
444
+
445
+ enum Op {
446
+ MirOp ( BinOp ) ,
447
+ MirOpBool ( BinOp ) ,
448
+ }
449
+ // The initial value is the neutral element.
450
+ let ( which, init) = match intrinsic_name {
451
+ "simd_reduce_and" => ( Op :: MirOp ( BinOp :: BitAnd ) , ImmTy :: from_int ( -1 , dest. layout ) ) ,
452
+ "simd_reduce_or" => ( Op :: MirOp ( BinOp :: BitOr ) , ImmTy :: from_int ( 0 , dest. layout ) ) ,
453
+ "simd_reduce_xor" => ( Op :: MirOp ( BinOp :: BitXor ) , ImmTy :: from_int ( 0 , dest. layout ) ) ,
454
+ "simd_reduce_any" => ( Op :: MirOpBool ( BinOp :: BitOr ) , imm_from_bool ( false ) ) ,
455
+ "simd_reduce_all" => ( Op :: MirOpBool ( BinOp :: BitAnd ) , imm_from_bool ( true ) ) ,
456
+ _ => unreachable ! ( ) ,
431
457
} ;
432
458
459
+ let mut res = init;
433
460
for i in 0 ..op_len {
434
461
let op = this. read_immediate ( & this. mplace_index ( & op, i) ?. into ( ) ) ?;
435
- let val = simd_element_to_bool ( op) ?;
436
- res = match intrinsic_name {
437
- "simd_reduce_any" => res | val,
438
- "simd_reduce_all" => res & val,
439
- _ => bug ! ( ) ,
462
+ res = match which {
463
+ Op :: MirOp ( mir_op) => {
464
+ this. binary_op ( mir_op, & res, & op) ?
465
+ }
466
+ Op :: MirOpBool ( mir_op) => {
467
+ let op = imm_from_bool ( simd_element_to_bool ( op) ?) ;
468
+ this. binary_op ( mir_op, & res, & op) ?
469
+ }
440
470
} ;
441
471
}
472
+ this. write_immediate ( * res, dest) ?;
473
+ }
474
+ #[ rustfmt:: skip]
475
+ | "simd_reduce_add_ordered"
476
+ | "simd_reduce_mul_ordered" => {
477
+ use mir:: BinOp ;
478
+
479
+ let & [ ref op, ref init] = check_arg_count ( args) ?;
480
+ let ( op, op_len) = this. operand_to_simd ( op) ?;
481
+ let init = this. read_immediate ( init) ?;
442
482
443
- this. write_scalar ( Scalar :: from_bool ( res) , dest) ?;
483
+ let mir_op = match intrinsic_name {
484
+ "simd_reduce_add_ordered" => BinOp :: Add ,
485
+ "simd_reduce_mul_ordered" => BinOp :: Mul ,
486
+ _ => unreachable ! ( ) ,
487
+ } ;
488
+
489
+ let mut res = init;
490
+ for i in 0 ..op_len {
491
+ let op = this. read_immediate ( & this. mplace_index ( & op, i) ?. into ( ) ) ?;
492
+ res = this. binary_op ( mir_op, & res, & op) ?;
493
+ }
494
+ this. write_immediate ( * res, dest) ?;
444
495
}
445
496
"simd_select" => {
446
497
let & [ ref mask, ref yes, ref no] = check_arg_count ( args) ?;
0 commit comments