simd函数分为这几类:计算,加载和存储(Load/Store),设置常量值(Set constants),提取部分值,类型转换,重新排列。
_mm256_add_epi32(a, b)
: — 将__m256i
参数当作 8个32-bit整型进行相加。 如果a数组包含的32-bit整型为 a0, a1, a2, a3, a4, a5, a6, a7 而 b数组包含的整型为 b0, b1, b2, b3, b4, b5, b6, b7, 返回 a0 + b0, a1 + b1, a2 + b2, a3 + b3, a4 + b4, a5 + b5, a6 + a6, a7 + b7。(汇编指令vpaddd
为类似的功能)_mm256_add_epi16(a, b)
: — 类似于_mm256_add_epi32
但是是将参数当作16个16-bit整型. 如果a数组包含的16-bit整型为 a0, a1, ..., a15 而 b数组包含的整型为 b0, b1, b2, ..., b15, 返回 a0 + b0, a1 + b1, ..., a15 + b15. (汇编指令vpaddw
为类似的功能)_mm256_add_epi8(a, b)
: — 类似于_mm256_add_epi32
但是参数当作32个8-bit整型。_mm256_mullo_epi16(x, y)
: 参数 x 和 y当作16-bit有符号整型数组, 将每对整数相乘,并将结果截断为 16-bit的整型。_mm256_mulhi_epi16(x, y)
: 参数 x 和 y当作16-bit有符号整型,将每对整数相乘得到一个 32 位整数,然后返回每个 32 位整数结果的前 16 位。_mm256_srli_epi16(x, N)
:参数 x 和 N 当作16-bit有符号整型,N为右移多少位的数组, a数组位a0,a1,...,a15而N数组为N0,N1,...,bN15,返回a0>>N0,a1>>N1,...,a15>>N15. (还有用于 32 或 64 位整数的 epi32 和 epi64 变体。)_mm256_slli_epi16(x, N)
: 类似于_mm256_srli_epi16(x, N)
,只不过是左移。_mm256_hadd_epi16(a, b)
: — (“horizontal add水平相加”) 将其__m128i
参数视为 16 位整数数组。 如果 a 数组包含 a0, a1, a2, a3, ..., a15 而 b 数组包含 b0, b1, b2, b3, ..., b15, 返回 a0 + a1, a2 + a3, a4 + a5, a6 + a7, b0 + b1, b2 + b3, b4 + b5, b6 + b7, a8 + a9, a10 + a11, a12 + a13, a14 + a15, b8 + b9, b10 + b11, b12 + b13, b14 + b15. (注意,这通常比_mm_add_epi16
慢得多。 (汇编指令vphaddw
指令。)
_mm256_setr_epi32
---- 通过 32-bit整数数组赋给__m256i
值。第一个整数参数在写入内存时在__m256i
的最低地址,然后依次填充。例如:
__m256i value1 = _mm256_setr_epi16(0, 1, 2, 3, 4, 5, 6, 7);
value1 中的值与 value2 中的值相同
int array[8] = {0, 1, 2, 3, 4, 5, 6, 7};
__m256i value2 = _mm256_loadu_si256((__m256i*) &array[0]);
_mm_setr_epi32
---- 通过 32-bit整数数组赋给__m128i
值。第一个整数参数在写入内存时在__m128i
的最低地址,然后依次填充例如:
__m128i value1 = _mm_setr_epi32(0, 1, 2, 3);
下面是等价的load代码:
int array[4] = {0, 1, 2, 3, 4, 5, 6, 7};
__m128i value2 = _mm_loadu_si128((__m256i*) &array[0]);
_mm256_setr_epi16
---- 类似于_mm256_setr_epi32
只不过通过16-bit整数数组赋值。例如:
__m256i value1 = _mm256_setr_epi16(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15);
下面的等价的load代码:
short array[8] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};
__m256i value2 = _mm256_loadu_si256((__m256i*) &array[0]);
-
_mm256_setr_epi8
,_mm_setr_epi8
---- 类似于_mm256_setr_epi32
/_mm_setr_epi32
但是是通过8-bit整型数组赋值。例如: -
_mm_set1_epi32
,_mm_set1_epi16
,_mm_set1_epi8
---- 给一个__m128i
赋值值,该值代表适当大小的值数组,其中数组的每个元素都具有相同的值。(有点类似于memset函数) 下面是例子:
__m128i value = _mm_set1_epi16(42);
等价于_mm_setr_epi16
赋值:
__m128i value = _mm_setr_epi16(42, 42, 42, 42, 42, 42, 42, 42);
_mm256_set_epi8
, 等等. — 类似于_mm256_setr_epi8
, 等. 但以相反的顺序获取其参数
更多细节需要参考intel的指令集文档。
_mm256_extract_epi32(a, index)
: 从 256-bit 向量 a 中提取索引为index的32-bit整数。如果将 a 复制到内存,则索引为 0 的整数将存储在最低内存地址处。索引必须是常量。
下面是编程案例:
__m256i a = _mm256_setr_epi32(0, 10, 20, 30, 40, 50, 60, 70);
int x = _mm256_extract_epi32(a, 2);
上面的x的值为20。
-
_mm_extract_epi32(a, index)
:从 128-bit 向量 a 中提取索引为index的32-bit整数。索引必须是常数。 -
_mm256_extract_epi16(a, index)
:类似于_mm256_extract_epi32
但是是提取16-bit整数。 -
_mm256_extracti128_si256(a, index)
:从 256-bit 向量 a 中提取索引为index的 128-bit 向量。索引必须是常数。
下面是例子:
__m256i a = _mm256_setr_epi32(0, 10, 20, 30, 40, 50, 60, 70);
__m128i result = _mm256_extracti128_si256(a, 1);
result其实是a向量的第一位的数组。
__m128i result = _mm_setr_epi32(40, 50, 60, 70);
类型转换用的较少。
_mm256_cvtepu8_epi16(eight_bit_numbers)
: 获取由 16 个 8-bit整型组成的 128-bit向量,并将其转换为由 16 个 16-bit有符号整数组成的 256-bit向量。 下面是实际例子:
__m128i value1 = _mm_setr_epi8(10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120, 130, 140, 150);
__m256i value2 = _mm256_cvtepu8_epi16(value1);
等价于如下:
__m256i value2 = _mm256_setr_epi16(10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120, 130, 140, 150);
_mm256_packus_epi16(a, b)
:获取 256-bit 向量 a 和 b 中的 所有16-bit 有符号整数,并将它们转换为 8 位无符号整数的 256-bit 向量。结果包含 a 的前 8 个整数、b 的前 8 个整数、a 的最后 8 个整数、b 的最后 8 个整数。超出范围的值设置为 255 或 0。
__m256i a = _mm256_setr_epi16(10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110, 120, 130, 140, 150, 160);
__m256i b = _mm256_setr_epi16(170, 180, 190, 200, 210, 220, 230, 240, 250, 260, 270, 25, 15, 5, -5, -15);
__m256i result = _mm256_packus_epi16(a, b)
下面的result可以直接设置:
__m256i result = _mm256_setr_epu8(
10, 20, 30, 40, 50, 60, 70, 80, /* first 8 integers from a */
170, 180, 190, 200, 210, 220, 230, 240, /* first eight integers from b */
90, 100, 110, 120, 130, 140, 150, /* last 8 integers from a */
250, 255, 255, 25, 15, 5, 0, 0, /* last 8 integers from b */
/* 260, 270 became 255; -5, -15 became 0 */
);
_mm256_zextsi128_si256(a)
: 获取 128-bit 向量 a 并通过添加 0 值 将其转换为 256-bit 向量。
这部分使用较少,不过多赘述了。