@@ -324,7 +324,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
324324 | "simd_shl"
325325 | "simd_shr"
326326 | "simd_and"
327- | "simd_or" => {
327+ | "simd_or"
328+ | "simd_eq" => {
328329 let & [ ref left, ref right] = check_arg_count ( args) ?;
329330 let ( left, left_len) = this. operand_to_simd ( left) ?;
330331 let ( right, right_len) = this. operand_to_simd ( right) ?;
@@ -343,6 +344,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
343344 "simd_shr" => mir:: BinOp :: Shr ,
344345 "simd_and" => mir:: BinOp :: BitAnd ,
345346 "simd_or" => mir:: BinOp :: BitOr ,
347+ "simd_eq" => mir:: BinOp :: Eq ,
346348 _ => unreachable ! ( ) ,
347349 } ;
348350
@@ -351,7 +353,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
351353 let right = this. read_immediate ( & this. mplace_index ( & right, i) ?. into ( ) ) ?;
352354 let dest = this. mplace_index ( & dest, i) ?;
353355 let ( val, overflowed, ty) = this. overflowing_binary_op ( op, & left, & right) ?;
354- assert_eq ! ( ty, dest. layout. ty) ;
355356 if matches ! ( op, mir:: BinOp :: Shl | mir:: BinOp :: Shr ) {
356357 // Shifts have extra UB as SIMD operations that the MIR binop does not have.
357358 // See <https://github.com/rust-lang/rust/issues/91237>.
@@ -360,8 +361,40 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
360361 throw_ub_format ! ( "overflowing shift by {} in `{}` in SIMD lane {}" , r_val, intrinsic_name, i) ;
361362 }
362363 }
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;
364395 }
396+
397+ this. write_scalar ( Scalar :: from_bool ( res) , dest) ?;
365398 }
366399
367400 // Atomic operations
0 commit comments