我有两个__m256i向量,用32个8位整数填充。像这样:
__int8 *a0 = new __int8[32] {2};
__int8 *a1 = new __int8[32] {3};
__m256i v0 = _mm256_loadu_si256((__m256i*)a0);
__m256i v1 = _mm256_loadu_si256((__m256i*)a1);
如何使用_mm256_mul_epi8(v0, v1)
(不存在)之类的方法或其他方法将这些向量相乘?
我想要2个结果向量,因为输出元素的宽度是输入元素宽度的两倍。或者只使用偶数输入元素(0、2、4等),可以与_mm_mul_epu32
类似地工作
答案 0 :(得分:3)
您想将结果分成两个向量,所以这是我对您的问题的建议。我试图做到清晰,简单和可实现:
#include <stdio.h>
#include <x86intrin.h>
void _mm256_print_epi8(__m256i );
void _mm256_print_epi16(__m256i );
void _mm256_mul_epi8(__m256i , __m256i , __m256i* , __m256i* );
int main()
{
char a0[32] = {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};
char a1[32] = {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, 33};
__m256i v0 = _mm256_loadu_si256((__m256i*) &a0[0]);
__m256i v1 = _mm256_loadu_si256((__m256i*) &a1[0]);
__m256i r0, r1;//for 16 bit results
_mm256_mul_epi8(v0, v1, &r0, &r1);
printf("\nv0 = ");_mm256_print_epi8(v0);
printf("\nv1 = ");_mm256_print_epi8(v1);
printf("\nr0 = ");_mm256_print_epi16(r0);
printf("\nr1 = ");_mm256_print_epi16(r1);
printf("\nfinished\n");
return 0;
}
//v0 and v1 are 8 bit input vectors. r0 and r1 are 18 bit results of multiplications
void _mm256_mul_epi8(__m256i v0, __m256i v1, __m256i* r0, __m256i* r1)
{
__m256i tmp0, tmp1;
__m128i m128_v0, m128_v1;
m128_v0 = _mm256_extractf128_si256 (v0, 0);
m128_v1 = _mm256_extractf128_si256 (v1, 0);
tmp0= _mm256_cvtepi8_epi16 (m128_v0); //printf("\ntmp0 = ");_mm256_print_epi16(tmp0);
tmp1= _mm256_cvtepi8_epi16 (m128_v1); //printf("\ntmp1 = ");_mm256_print_epi16(tmp1);
*r0 =_mm256_mullo_epi16(tmp0, tmp1);
m128_v0 = _mm256_extractf128_si256 (v0, 1);
m128_v1 = _mm256_extractf128_si256 (v1, 1);
tmp0= _mm256_cvtepi8_epi16 (m128_v0); //printf("\ntmp0 = ");_mm256_print_epi16(tmp0);
tmp1= _mm256_cvtepi8_epi16 (m128_v1); //printf("\ntmp1 = ");_mm256_print_epi16(tmp1);
*r1 =_mm256_mullo_epi16(tmp0, tmp1);
}
void _mm256_print_epi8(__m256i vec)
{
char temp[32];
_mm256_storeu_si256((__m256i*)&temp[0], vec);
int i;
for(i=0; i<32; i++)
printf(" %3i,", temp[i]);
}
void _mm256_print_epi16(__m256i vec)
{
short temp[16];
_mm256_storeu_si256((__m256i*)&temp[0], vec);
int i;
for(i=0; i<16; i++)
printf(" %3i,", temp[i]);
}
输出为:
[martin@mrt Stack over flow]$ gcc -O2 -march=native mul_epi8.c -o out
[martin@mrt Stack over flow]$ ./out
v0 = 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,
v1 = 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, 33,
r0 = 2, 6, 12, -20, 30, 42, 56, 72, 90, -110, 132, -156, 182, 210, 240, 272,
r1 = 306, 342, -380, 420, 462, 506, 552, 600, 650, 702, 756, 812, 870, 930, 992, 1056,
finished
[martin@mrt Stack over flow]$
注意::我已在推荐代码中注释了中间结果tmp0和tmp1。 另外,正如彼得在注释中所建议的那样,并提供了一个可实现的链接,如果您的程序从内存中加载并且您不需要在向量中乘以元素,则可以使用以下代码:
#include <immintrin.h>
//v0 and v1 are 8 bit input vectors. r0 and r1 are 18 bit results of multiplications
__m256i mul_epi8_to_16(__m128i v0, __m128i v1)
{
__m256i tmp0 = _mm256_cvtepi8_epi16 (v0); //printf("\ntmp0 = ");_mm256_print_epi16(tmp0);
__m256i tmp1 = _mm256_cvtepi8_epi16 (v1); //printf("\ntmp1 = ");_mm256_print_epi16(tmp1);
return _mm256_mullo_epi16(tmp0, tmp1);
}
__m256i mul_epi8_to_16_memsrc(char *__restrict a, char *__restrict b){
__m128i v0 = _mm_loadu_si128((__m128i*) a);
__m128i v1 = _mm_loadu_si128((__m128i*) b);
return mul_epi8_to_16(v0, v1);
}
int main()
{
char a0[32] = {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};
char a1[32] = {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, 33};
__m256i r0 = mul_epi8_to_16_memsrc(a0, a1);
}