@@ -88,8 +88,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
88
88
this. write_immediate ( res, & dest) ?;
89
89
}
90
90
}
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" => {
93
93
let [ left, right] =
94
94
this. check_shim ( abi, Abi :: C { unwind : false } , link_name, args) ?;
95
95
@@ -101,35 +101,35 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
101
101
assert_eq ! ( dest_len, right_len) ;
102
102
103
103
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) ?) ?;
106
106
let dest = this. project_index ( & dest, i) ?;
107
107
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) ?;
124
113
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
+ ) ?;
129
126
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) ?;
133
133
}
134
134
}
135
135
// Used to implement the _mm_mul_epu32 function.
0 commit comments