Implement the llvm.x86.sse2.pmadd.wd intrinsic
This commit is contained in:
parent
e86c68aa54
commit
0c0c088e57
2 changed files with 54 additions and 0 deletions
|
|
@ -82,6 +82,42 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>:
|
|||
this.write_immediate(*res, &dest)?;
|
||||
}
|
||||
}
|
||||
// Used to implement the _mm_madd_epi16 function.
|
||||
// Multiplies packed signed 16-bit integers in `left` and `right`, producing
|
||||
// intermediate signed 32-bit integers. Horizontally add adjacent pairs of
|
||||
// intermediate 32-bit integers, and pack the results in `dest`.
|
||||
"pmadd.wd" => {
|
||||
let [left, right] =
|
||||
this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?;
|
||||
|
||||
let (left, left_len) = this.operand_to_simd(left)?;
|
||||
let (right, right_len) = this.operand_to_simd(right)?;
|
||||
let (dest, dest_len) = this.place_to_simd(dest)?;
|
||||
|
||||
assert_eq!(left_len, right_len);
|
||||
assert_eq!(dest_len.checked_mul(2).unwrap(), left_len);
|
||||
|
||||
for i in 0..dest_len {
|
||||
let j1 = i.checked_mul(2).unwrap();
|
||||
let left1 = this.read_scalar(&this.project_index(&left, j1)?)?.to_i16()?;
|
||||
let right1 = this.read_scalar(&this.project_index(&right, j1)?)?.to_i16()?;
|
||||
|
||||
let j2 = j1.checked_add(1).unwrap();
|
||||
let left2 = this.read_scalar(&this.project_index(&left, j2)?)?.to_i16()?;
|
||||
let right2 = this.read_scalar(&this.project_index(&right, j2)?)?.to_i16()?;
|
||||
|
||||
let dest = this.project_index(&dest, i)?;
|
||||
|
||||
// Multiplications are i16*i16->i32, which will not overflow.
|
||||
let mul1 = i32::from(left1).checked_mul(right1.into()).unwrap();
|
||||
let mul2 = i32::from(left2).checked_mul(right2.into()).unwrap();
|
||||
// However, this addition can overflow in the most extreme case
|
||||
// (-0x8000)*(-0x8000)+(-0x8000)*(-0x8000) = 0x80000000
|
||||
let res = mul1.wrapping_add(mul2);
|
||||
|
||||
this.write_scalar(Scalar::from_i32(res), &dest)?;
|
||||
}
|
||||
}
|
||||
// Used to implement the _mm_mulhi_epi16 and _mm_mulhi_epu16 functions.
|
||||
"pmulh.w" | "pmulhu.w" => {
|
||||
let [left, right] =
|
||||
|
|
|
|||
|
|
@ -70,6 +70,24 @@ mod tests {
|
|||
}
|
||||
test_mm_avg_epu16();
|
||||
|
||||
#[target_feature(enable = "sse2")]
|
||||
unsafe fn test_mm_madd_epi16() {
|
||||
let a = _mm_setr_epi16(1, 2, 3, 4, 5, 6, 7, 8);
|
||||
let b = _mm_setr_epi16(9, 10, 11, 12, 13, 14, 15, 16);
|
||||
let r = _mm_madd_epi16(a, b);
|
||||
let e = _mm_setr_epi32(29, 81, 149, 233);
|
||||
assert_eq_m128i(r, e);
|
||||
|
||||
let a =
|
||||
_mm_setr_epi16(i16::MAX, i16::MAX, i16::MIN, i16::MIN, i16::MIN, i16::MAX, 0, 0);
|
||||
let b =
|
||||
_mm_setr_epi16(i16::MAX, i16::MAX, i16::MIN, i16::MIN, i16::MAX, i16::MIN, 0, 0);
|
||||
let r = _mm_madd_epi16(a, b);
|
||||
let e = _mm_setr_epi32(0x7FFE0002, i32::MIN, -0x7FFF0000, 0);
|
||||
assert_eq_m128i(r, e);
|
||||
}
|
||||
test_mm_madd_epi16();
|
||||
|
||||
#[target_feature(enable = "sse2")]
|
||||
unsafe fn test_mm_mulhi_epi16() {
|
||||
let (a, b) = (_mm_set1_epi16(1000), _mm_set1_epi16(-1001));
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue