@@ -324,7 +324,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
324
324
| "simd_shl"
325
325
| "simd_shr"
326
326
| "simd_and"
327
- | "simd_or" => {
327
+ | "simd_or"
328
+ | "simd_eq" => {
328
329
let & [ ref left, ref right] = check_arg_count ( args) ?;
329
330
let ( left, left_len) = this. operand_to_simd ( left) ?;
330
331
let ( right, right_len) = this. operand_to_simd ( right) ?;
@@ -343,6 +344,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
343
344
"simd_shr" => mir:: BinOp :: Shr ,
344
345
"simd_and" => mir:: BinOp :: BitAnd ,
345
346
"simd_or" => mir:: BinOp :: BitOr ,
347
+ "simd_eq" => mir:: BinOp :: Eq ,
346
348
_ => unreachable ! ( ) ,
347
349
} ;
348
350
@@ -351,7 +353,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
351
353
let right = this. read_immediate ( & this. mplace_index ( & right, i) ?. into ( ) ) ?;
352
354
let dest = this. mplace_index ( & dest, i) ?;
353
355
let ( val, overflowed, ty) = this. overflowing_binary_op ( op, & left, & right) ?;
354
- assert_eq ! ( ty, dest. layout. ty) ;
355
356
if matches ! ( op, mir:: BinOp :: Shl | mir:: BinOp :: Shr ) {
356
357
// Shifts have extra UB as SIMD operations that the MIR binop does not have.
357
358
// See <https://github.com/rust-lang/rust/issues/91237>.
@@ -360,8 +361,40 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
360
361
throw_ub_format ! ( "overflowing shift by {} in `{}` in SIMD lane {}" , r_val, intrinsic_name, i) ;
361
362
}
362
363
}
363
- this. write_scalar ( val, & dest. into ( ) ) ?;
364
+ if matches ! ( op, mir:: BinOp :: Eq ) {
365
+ // Special handling for boolean-returning operations
366
+ assert_eq ! ( ty, this. tcx. types. bool ) ;
367
+ let val = val. to_bool ( ) . unwrap ( ) ;
368
+ let val = if val { -1 } else { 0 } ; // SIMD uses all-1 as pattern for "true"
369
+ let val = Scalar :: from_int ( val, dest. layout . size ) ;
370
+ this. write_scalar ( val, & dest. into ( ) ) ?;
371
+ } else {
372
+ assert_eq ! ( ty, dest. layout. ty) ;
373
+ this. write_scalar ( val, & dest. into ( ) ) ?;
374
+ }
375
+ }
376
+ }
377
+ "simd_reduce_any" => {
378
+ let & [ ref arg] = check_arg_count ( args) ?;
379
+ let ( arg, arg_len) = this. operand_to_simd ( arg) ?;
380
+
381
+ let mut res = false ; // the neutral element
382
+ for i in 0 ..arg_len {
383
+ let op = this. read_immediate ( & this. mplace_index ( & arg, i) ?. into ( ) ) ?;
384
+ // We convert it to a *signed* integer and expect either 0 or -1 (the latter means all bits were set).
385
+ let val = op. to_scalar ( ) ?. to_int ( op. layout . size ) ?;
386
+ let val = match val {
387
+ 0 => false ,
388
+ -1 => true ,
389
+ _ =>
390
+ throw_ub_format ! (
391
+ "each element of a simd_reduce_any operand must be all-0-bits or all-1-bits"
392
+ ) ,
393
+ } ;
394
+ res = res | val;
364
395
}
396
+
397
+ this. write_scalar ( Scalar :: from_bool ( res) , dest) ?;
365
398
}
366
399
367
400
// Atomic operations
0 commit comments