miri: reduce code duplication in SSE2 pmulh.w and pmulhu.w
Not really a saving in terms of lines of code, but at least the logic is de-duplicated
This commit is contained in:
parent
8d590f2fa8
commit
9fbbfd2e39
@ -88,8 +88,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||||||
this.write_immediate(res, &dest)?;
|
this.write_immediate(res, &dest)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Used to implement the _mm_mulhi_epi16 function.
|
// Used to implement the _mm_mulhi_epi16 and _mm_mulhi_epu16 functions.
|
||||||
"pmulh.w" => {
|
"pmulh.w" | "pmulhu.w" => {
|
||||||
let [left, right] =
|
let [left, right] =
|
||||||
this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
|
this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
|
||||||
|
|
||||||
@ -101,35 +101,35 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||||||
assert_eq!(dest_len, right_len);
|
assert_eq!(dest_len, right_len);
|
||||||
|
|
||||||
for i in 0..dest_len {
|
for i in 0..dest_len {
|
||||||
let left = this.read_scalar(&this.project_index(&left, i)?)?.to_i16()?;
|
let left = this.read_immediate(&this.project_index(&left, i)?)?;
|
||||||
let right = this.read_scalar(&this.project_index(&right, i)?)?.to_i16()?;
|
let right = this.read_immediate(&this.project_index(&right, i)?)?;
|
||||||
let dest = this.project_index(&dest, i)?;
|
let dest = this.project_index(&dest, i)?;
|
||||||
|
|
||||||
// Values are expanded from i16 to i32, so multiplication cannot overflow.
|
// Widen the operands to avoid overflow
|
||||||
let res = i32::from(left).checked_mul(i32::from(right)).unwrap() >> 16;
|
let twice_wide_ty = this.get_twice_wide_int_ty(left.layout.ty);
|
||||||
this.write_scalar(Scalar::from_i16(res.try_into().unwrap()), &dest)?;
|
let twice_wide_layout = this.layout_of(twice_wide_ty)?;
|
||||||
}
|
let left = this.int_to_int_or_float(&left, twice_wide_ty)?;
|
||||||
}
|
let right = this.int_to_int_or_float(&right, twice_wide_ty)?;
|
||||||
// Used to implement the _mm_mulhi_epu16 function.
|
|
||||||
"pmulhu.w" => {
|
|
||||||
let [left, right] =
|
|
||||||
this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
|
|
||||||
|
|
||||||
let (left, left_len) = this.operand_to_simd(left)?;
|
// Multiply
|
||||||
let (right, right_len) = this.operand_to_simd(right)?;
|
let (multiplied, _overflow, _ty) = this.overflowing_binary_op(
|
||||||
let (dest, dest_len) = this.place_to_simd(dest)?;
|
mir::BinOp::Mul,
|
||||||
|
&ImmTy::from_immediate(left, twice_wide_layout),
|
||||||
|
&ImmTy::from_immediate(right, twice_wide_layout),
|
||||||
|
)?;
|
||||||
|
// Keep the high half
|
||||||
|
let (high, _overflow, _ty) = this.overflowing_binary_op(
|
||||||
|
mir::BinOp::Shr,
|
||||||
|
&ImmTy::from_scalar(multiplied, twice_wide_layout),
|
||||||
|
&ImmTy::from_uint(dest.layout.size.bits(), twice_wide_layout),
|
||||||
|
)?;
|
||||||
|
|
||||||
assert_eq!(dest_len, left_len);
|
// Narrow back to the original type
|
||||||
assert_eq!(dest_len, right_len);
|
let res = this.int_to_int_or_float(
|
||||||
|
&ImmTy::from_scalar(high, twice_wide_layout),
|
||||||
for i in 0..dest_len {
|
dest.layout.ty,
|
||||||
let left = this.read_scalar(&this.project_index(&left, i)?)?.to_u16()?;
|
)?;
|
||||||
let right = this.read_scalar(&this.project_index(&right, i)?)?.to_u16()?;
|
this.write_immediate(res, &dest)?;
|
||||||
let dest = this.project_index(&dest, i)?;
|
|
||||||
|
|
||||||
// Values are expanded from u16 to u32, so multiplication cannot overflow.
|
|
||||||
let res = u32::from(left).checked_mul(u32::from(right)).unwrap() >> 16;
|
|
||||||
this.write_scalar(Scalar::from_u16(res.try_into().unwrap()), &dest)?;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Used to implement the _mm_mul_epu32 function.
|
// Used to implement the _mm_mul_epu32 function.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user