c++ - AVX2 有符号 8 位元素的整数乘法,产生有符号 16 位结果?
问题描述
我有两个 __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 个结果向量,因为输出元素宽度是输入元素宽度的两倍。或者类似的东西_mm_mul_epu32
可以,只使用偶数输入元素(0、2、4等)
解决方案
您希望将结果分成两个向量,所以这是我对您的问题的建议。我试图清楚、简单和可实现:
#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。此外,正如彼得在评论中所建议并提供了一个godbolt链接,如果您的程序从内存中加载并且您不需要将向量中的元素相乘,您可以使用以下代码:
#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);
}
推荐阅读
- reactjs - 通过访问 this.state 在状态中设置索引
- r - 如何将 2D 数据帧转换为 3D 矩阵,保留行和列顺序
- code-coverage - 通过 CircleCI 中的赛普拉斯代码覆盖插件运行时,纽约报告失败并显示 ENOENT
- ruby-on-rails - 为什么我的多对多集合没有通过?
- python - 从 Python 到 SQL(Aginity、Netezza)的 CREATE/DROP 调用不起作用
- javascript - Vue-tables-2 options.hiddenColumns 不起作用
- python - 列表、字典和元组值
- php - WHMCS - 将客户名称和电子邮件添加到附属页面
- r - 有没有办法找到并删除 R 中分组 ID 的奇数行?
- snowflake-cloud-data-platform - Snowflake my_var 中的元组类型