@@ -306,7 +306,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
306306 }
307307
308308 // SIMD operations
309- "simd_add" | "simd_sub" | "simd_mul" | "simd_div" | "simd_rem" => {
309+ #[ rustfmt:: skip]
310+ | "simd_add"
311+ | "simd_sub"
312+ | "simd_mul"
313+ | "simd_div"
314+ | "simd_rem"
315+ | "simd_shl"
316+ | "simd_shr" => {
310317 let & [ ref left, ref right] = check_arg_count ( args) ?;
311318 let ( left, left_len) = this. operand_to_simd ( left) ?;
312319 let ( right, right_len) = this. operand_to_simd ( right) ?;
@@ -321,14 +328,26 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
321328 "simd_mul" => mir:: BinOp :: Mul ,
322329 "simd_div" => mir:: BinOp :: Div ,
323330 "simd_rem" => mir:: BinOp :: Rem ,
331+ "simd_shl" => mir:: BinOp :: Shl ,
332+ "simd_shr" => mir:: BinOp :: Shr ,
324333 _ => unreachable ! ( ) ,
325334 } ;
326335
327336 for i in 0 ..dest_len {
328337 let left = this. read_immediate ( & this. mplace_index ( & left, i) ?. into ( ) ) ?;
329338 let right = this. read_immediate ( & this. mplace_index ( & right, i) ?. into ( ) ) ?;
330- let dest = this. mplace_index ( & dest, i) ?. into ( ) ;
331- this. binop_ignore_overflow ( op, & left, & right, & dest) ?;
339+ let dest = this. mplace_index ( & dest, i) ?;
340+ let ( val, overflowed, ty) = this. overflowing_binary_op ( op, & left, & right) ?;
341+ assert_eq ! ( ty, dest. layout. ty) ;
342+ if matches ! ( op, mir:: BinOp :: Shl | mir:: BinOp :: Shr ) {
343+ // Shifts have extra UB as SIMD operations that the MIR binop does not have.
344+ // See <https://github.com/rust-lang/rust/issues/91237>.
345+ if overflowed {
346+ let r_val = right. to_scalar ( ) ?. to_bits ( right. layout . size ) ?;
347+ throw_ub_format ! ( "overflowing shift by {} in `{}` in SIMD lane {}" , r_val, intrinsic_name, i) ;
348+ }
349+ }
350+ this. write_scalar ( val, & dest. into ( ) ) ?;
332351 }
333352 }
334353
0 commit comments