@@ -88,8 +88,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
8888 this. write_immediate ( res, & dest) ?;
8989 }
9090 }
91- // Used to implement the _mm_mulhi_epi16 function .
92- "pmulh.w" => {
91+ // Used to implement the _mm_mulhi_epi16 and _mm_mulhi_epu16 functions .
92+ "pmulh.w" | "pmulhu.w" => {
9393 let [ left, right] =
9494 this. check_shim ( abi, Abi :: C { unwind : false } , link_name, args) ?;
9595
@@ -101,35 +101,35 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
101101 assert_eq ! ( dest_len, right_len) ;
102102
103103 for i in 0 ..dest_len {
104- let left = this. read_scalar ( & this. project_index ( & left, i) ?) ? . to_i16 ( ) ?;
105- let right = this. read_scalar ( & this. project_index ( & right, i) ?) ? . to_i16 ( ) ?;
104+ let left = this. read_immediate ( & this. project_index ( & left, i) ?) ?;
105+ let right = this. read_immediate ( & this. project_index ( & right, i) ?) ?;
106106 let dest = this. project_index ( & dest, i) ?;
107107
108- // Values are expanded from i16 to i32, so multiplication cannot overflow.
109- let res = i32:: from ( left) . checked_mul ( i32:: from ( right) ) . unwrap ( ) >> 16 ;
110- this. write_scalar ( Scalar :: from_i16 ( res. try_into ( ) . unwrap ( ) ) , & dest) ?;
111- }
112- }
113- // Used to implement the _mm_mulhi_epu16 function.
114- "pmulhu.w" => {
115- let [ left, right] =
116- this. check_shim ( abi, Abi :: C { unwind : false } , link_name, args) ?;
117-
118- let ( left, left_len) = this. operand_to_simd ( left) ?;
119- let ( right, right_len) = this. operand_to_simd ( right) ?;
120- let ( dest, dest_len) = this. place_to_simd ( dest) ?;
121-
122- assert_eq ! ( dest_len, left_len) ;
123- assert_eq ! ( dest_len, right_len) ;
108+ // Widen the operands to avoid overflow
109+ let twice_wide_ty = this. get_twice_wide_int_ty ( left. layout . ty ) ;
110+ let twice_wide_layout = this. layout_of ( twice_wide_ty) ?;
111+ let left = this. int_to_int_or_float ( & left, twice_wide_ty) ?;
112+ let right = this. int_to_int_or_float ( & right, twice_wide_ty) ?;
124113
125- for i in 0 ..dest_len {
126- let left = this. read_scalar ( & this. project_index ( & left, i) ?) ?. to_u16 ( ) ?;
127- let right = this. read_scalar ( & this. project_index ( & right, i) ?) ?. to_u16 ( ) ?;
128- let dest = this. project_index ( & dest, i) ?;
114+ // Multiply
115+ let ( multiplied, _overflow, _ty) = this. overflowing_binary_op (
116+ mir:: BinOp :: Mul ,
117+ & ImmTy :: from_immediate ( left, twice_wide_layout) ,
118+ & ImmTy :: from_immediate ( right, twice_wide_layout) ,
119+ ) ?;
120+ // Keep the high half
121+ let ( high, _overflow, _ty) = this. overflowing_binary_op (
122+ mir:: BinOp :: Shr ,
123+ & ImmTy :: from_scalar ( multiplied, twice_wide_layout) ,
124+ & ImmTy :: from_uint ( dest. layout . size . bits ( ) , twice_wide_layout) ,
125+ ) ?;
129126
130- // Values are expanded from u16 to u32, so multiplication cannot overflow.
131- let res = u32:: from ( left) . checked_mul ( u32:: from ( right) ) . unwrap ( ) >> 16 ;
132- this. write_scalar ( Scalar :: from_u16 ( res. try_into ( ) . unwrap ( ) ) , & dest) ?;
127+ // Narrow back to the original type
128+ let res = this. int_to_int_or_float (
129+ & ImmTy :: from_scalar ( high, twice_wide_layout) ,
130+ dest. layout . ty ,
131+ ) ?;
132+ this. write_immediate ( res, & dest) ?;
133133 }
134134 }
135135 // Used to implement the _mm_mul_epu32 function.
0 commit comments