两个16位整数矢量与C ++中的AVX2的内积

问题描述 投票:0回答:1

我正在寻找最有效的方法来将两个对齐的int16_t数组相乘,其长度可以用AVX2除以16。

[乘以向量x之后,我从_mm256_extracti128_si256_mm256_castsi256_si128开始具有x的低部分和高部分,并与_mm_add_epi16相加。

我复制了结果寄存器,并将_mm_move_epi64应用于原始寄存器,并再次将其与_mm_add_epi16相加。现在,我认为我有:-,-,-,-,x15 + x7 + x11 + x3,x14 + x6 + x10 + x2,x13 + x5 + x9 + x1,x12 + x4 + x8 + x0在128位寄存器中。但是现在我陷入困境,不知道如何有效地总结剩余的四个条目以及如何提取16位结果。您能帮我吗?

UPDATE按照谷歌的意见和小时我的工作解决方案:

// AVX multiply
hash = 1;
start1 = std::chrono::high_resolution_clock::now();
for(int i=0; i<2000000; i++) {
    ZTYPE*  xv = al_entr1.c.data();
    ZTYPE*  yv = al_entr2.c.data();

    __m256i tres = _mm256_setzero_si256();
    for(int ii=0; ii < MAX_SIEVING_DIM; ii = ii+16/*8*/)
    {
        // editor's note: alignment required.  Use loadu for unaligned
        __m256i  xr = _mm256_load_si256((__m256i*)(xv+ii));
        __m256i  yr = _mm256_load_si256((__m256i*)(yv+ii));
        const __m256i tmp = _mm256_madd_epi16 (xr, yr);
        tres =  _mm256_add_epi32(tmp, tres);
    }

    // Reduction
    const __m128i x128 = _mm_add_epi32  ( _mm256_extracti128_si256(tres, 1), _mm256_castsi256_si128(tres));
    const __m128i x128_up = _mm_shuffle_epi32(x128, 78);
    const __m128i x64  = _mm_add_epi32  (x128, x128_up);
    const __m128i _x32 =  _mm_hadd_epi32(x64, x64);

    const int res = _mm_extract_epi32(_x32, 0);
    hash |= res;
}

finish1 = std::chrono::high_resolution_clock::now();
elapsed1 = finish1 - start1;
std::cout << "AVX multiply: " <<elapsed1.count() << " sec. (" << hash << ")" << std::endl;

至少是到目前为止最快的解决方案:

  • std :: inner_product:0.819781秒。 (-14335)
  • std :: inner_product(对齐):0.964058秒。 (-14335)
  • 天真乘法:0.588623秒。 (-14335)
  • 展开倍数:0.505639秒。 (-14335)
  • AVX乘以:0.0488352秒。 (-14335)
vectorization sse simd avx2 inner-product
1个回答
0
投票

按照google的评论和工作时间,我的工作解决方案:

// AVX multiply
hash = 1;
start1 = std::chrono::high_resolution_clock::now();
for(int i=0; i<2000000; i++) {
    ZTYPE*  xv = al_entr1.c.data();
    ZTYPE*  yv = al_entr2.c.data();

    __m256i tres = _mm256_setzero_si256();
    for(int ii=0; ii < MAX_SIEVING_DIM; ii = ii+16/*8*/)
    {
        // editor's note: alignment required.  Use loadu for unaligned
        __m256i  xr = _mm256_load_si256((__m256i*)(xv+ii));
        __m256i  yr = _mm256_load_si256((__m256i*)(yv+ii));
        const __m256i tmp = _mm256_madd_epi16 (xr, yr);
        tres =  _mm256_add_epi32(tmp, tres);
    }

    // Reduction
    const __m128i x128 = _mm_add_epi32  ( _mm256_extracti128_si256(tres, 1), _mm256_castsi256_si128(tres));
    const __m128i x128_up = _mm_shuffle_epi32(x128, 78);
    const __m128i x64  = _mm_add_epi32  (x128, x128_up);
    const __m128i _x32 =  _mm_hadd_epi32(x64, x64);

    const int res = _mm_extract_epi32(_x32, 0);
    hash |= res;
}

finish1 = std::chrono::high_resolution_clock::now();
elapsed1 = finish1 - start1;
std::cout << "AVX multiply: " <<elapsed1.count() << " sec. (" << hash << ")" << std::endl;

至少是到目前为止最快的解决方案:

  • std :: inner_product:0.819781秒。 (-14335)
  • std :: inner_product(对齐):0.964058秒。 (-14335)
  • 天真乘法:0.588623秒。 (-14335)
  • 展开倍数:0.505639秒。 (-14335)
  • AVX乘以:0.0488352秒。 (-14335)
© www.soinside.com 2019 - 2024. All rights reserved.