avx2: _mm256_alignr_epi8

This commit is contained in:
gwenn 2017-09-30 16:21:42 +02:00 committed by Andrew Gallant
parent be7f29da03
commit 3202558c98
2 changed files with 100 additions and 1 deletions

View file

@ -10,6 +10,7 @@ extern "platform-intrinsic" {
pub fn simd_shuffle4<T, U>(x: T, y: T, idx: [u32; 4]) -> U;
pub fn simd_shuffle8<T, U>(x: T, y: T, idx: [u32; 8]) -> U;
pub fn simd_shuffle16<T, U>(x: T, y: T, idx: [u32; 16]) -> U;
pub fn simd_shuffle32<T, U>(x: T, y: T, idx: [u32; 32]) -> U;
pub fn simd_insert<T, U>(x: T, idx: u32, val: U) -> T;
pub fn simd_extract<T, U>(x: T, idx: u32) -> U;

View file

@ -1,3 +1,4 @@
use simd_llvm::simd_shuffle32;
use v256::*;
use v128::*;
use x86::__m256i;
@ -93,7 +94,61 @@ pub unsafe fn _mm256_adds_epu16(a: u16x16, b: u16x16) -> u16x16 {
paddusw(a, b)
}
// TODO _mm256_alignr_epi8
/// Concatenate pairs of 16-byte blocks in `a` and `b` into a 32-byte temporary result,
/// shift the result right by `n` bytes, and return the low 16 bytes.
#[inline(always)]
#[target_feature = "+avx2"]
#[cfg_attr(test, assert_instr(vpalignr, n = 15))]
pub unsafe fn _mm256_alignr_epi8(a: i8x32, b: i8x32, n: i32) -> i8x32 {
let n = n as u32;
// If palignr is shifting the pair of vectors more than the size of two
// lanes, emit zero.
if n > 32 {
return i8x32::splat(0);
}
// If palignr is shifting the pair of input vectors more than one lane,
// but less than two lanes, convert to shifting in zeroes.
let (a, b, n) = if n > 16 {
(i8x32::splat(0), a, n - 16)
} else {
(a, b, n)
};
const fn add(a: u32, b: u32) -> u32 { a + b }
macro_rules! shuffle {
($shift:expr) => {
simd_shuffle32(b, a, [
add(0, $shift), add(1, $shift),
add(2, $shift), add(3, $shift),
add(4, $shift), add(5, $shift),
add(6, $shift), add(7, $shift),
add(8, $shift), add(9, $shift),
add(10, $shift), add(11, $shift),
add(12, $shift), add(13, $shift),
add(14, $shift), add(15, $shift),
add(16, $shift), add(17, $shift),
add(18, $shift), add(19, $shift),
add(20, $shift), add(21, $shift),
add(22, $shift), add(23, $shift),
add(24, $shift), add(25, $shift),
add(26, $shift), add(27, $shift),
add(28, $shift), add(29, $shift),
add(30, $shift), add(31, $shift),
])
}
}
match n {
0 => shuffle!(0), 1 => shuffle!(1),
2 => shuffle!(2), 3 => shuffle!(3),
4 => shuffle!(4), 5 => shuffle!(5),
6 => shuffle!(6), 7 => shuffle!(7),
8 => shuffle!(8), 9 => shuffle!(9),
10 => shuffle!(10), 11 => shuffle!(11),
12 => shuffle!(12), 13 => shuffle!(13),
14 => shuffle!(14), 15 => shuffle!(15),
_ => shuffle!(16),
}
}
/// Compute the bitwise AND of 256 bits (representing integer data)
/// in `a` and `b`.
@ -2103,4 +2158,47 @@ mod tests {
let r = avx2::_mm256_xor_si256(a, b);
assert_eq!(r, __m256i::splat(6));
}
#[simd_test = "avx2"]
unsafe fn _mm256_alignr_epi8() {
let a = i8x32::new(
1, 2, 3, 4, 5, 6, 7, 8,
9, 10, 11, 12, 13, 14, 15, 16,
17, 18, 19, 20, 21, 22, 23, 24,
25, 26, 27, 28, 29, 30, 31, 32);
let b = i8x32::new(
-1, -2, -3, -4, -5, -6, -7, -8,
-9, -10, -11, -12, -13, -14, -15, -16,
-17, -18, -19, -20, -21, -22, -23, -24,
-25, -26, -27, -28, -29, -30, -31, -32);
let r = avx2::_mm256_alignr_epi8(a, b, 33);
assert_eq!(r, i8x32::splat(0));
let r = avx2::_mm256_alignr_epi8(a, b, 17);
let expected = i8x32::new(
2, 3, 4, 5, 6, 7, 8, 9,
10, 11, 12, 13, 14, 15, 16, 17,
18, 19, 20, 21, 22, 23, 24, 25,
26, 27, 28, 29, 30, 31, 32, 0);
assert_eq!(r, expected);
let expected = i8x32::new(
-17, -18, -19, -20, -21, -22, -23, -24,
-25, -26, -27, -28, -29, -30, -31, -32,
1, 2, 3, 4, 5, 6, 7, 8,
9, 10, 11, 12, 13, 14, 15, 16);
let r = avx2::_mm256_alignr_epi8(a, b, 16);
assert_eq!(r, expected);
let r = avx2::_mm256_alignr_epi8(a, b, 15);
let expected = i8x32::new(
-16, -17, -18, -19, -20, -21, -22, -23,
-24, -25, -26, -27, -28, -29, -30, -31,
-32, 1, 2, 3, 4, 5, 6, 7,
8, 9, 10, 11, 12, 13, 14, 15);
assert_eq!(r, expected);
let r = avx2::_mm256_alignr_epi8(a, b, 0);
assert_eq!(r, b);
}
}