AVX2带符号的8位元素的整数乘法,产生带符号的16位结果? [英] AVX2 integer multiply of signed 8-bit elements, producing signed 16-bit results?

查看:69
本文介绍了AVX2带符号的8位元素的整数乘法,产生带符号的16位结果?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有两个__m256i向量,用32个8位整数填充.像这样:

I have two __m256i vectors, filled with 32 8-bit integers. Something like this:

    __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)(不存在)或任何其他方式将这些向量相乘?

How can i multiply these vectors, using something like _mm256_mul_epi8(v0, v1) (which does not exist) or any another way?

我想要2个结果向量,因为输出元素的宽度是输入元素宽度的两倍.或与 _mm_mul_epu32 类似的事情可以,仅使用偶数输入元素(0、2、4等)即可.

I want 2 vectors of results, because the output element width is twice the input element width. Or something that works similarly to _mm_mul_epu32 would be ok, using only the even input elements (0, 2, 4, etc.)

推荐答案

您希望将结果分成两个向量,所以这是我对您的问题的建议.我试图做到清晰,简单和可实现:

You want the result separated in two vectors so this is my suggestion for your question. I've tried to be clear, simple and realizable:

#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链接,如果您的程序从内存加载,并且您不需要在向量中乘以元素,则可以使用以下代码:

NOTE: I've commented the intermediate results tmp0 and tmp1 in the recommended code. In addition, as peter suggested in comments and provided a godbolt link, if your program loads from memory and you don't need to multiply elements in vectors you can use this code:

#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);

}

这篇关于AVX2带符号的8位元素的整数乘法,产生带符号的16位结果?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆