assembly AVX2混洗数据

umuewwlo  于 2023-02-19  发布在  其他
关注(0)|答案(1)|浏览(113)

例如,
第一名:0 2 4 6 8 10 12 14 16 18 20 22 24 26 28 30
第二名:1 3 5 7 9 11 13 15 17 19 21 23 25 27 29 31
变更为↓
第三名:0 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
AVX2指令集是否有满足此要求的指令?
我找了官方手册,但是没有找到。我在网上找了很长时间。但是没有用。请帮助或尝试给一些想法如何实现这一点。
谢谢!
我找了官方手册,但是没有找到。我在网上找了很长时间。但是没有用。请帮助或尝试给一些想法如何实现这一点。

n3schb8v

n3schb8v1#

AVX使用128位通道,这使得这个操作令人惊讶的乏味。通常更容易考虑两个向量的顺序

---------------------
|    A    |    C    |
---------------------

---------------------
|    B    |    D    |
---------------------

而不是

---------------------
|    A    |    B    |
---------------------

---------------------
|    C    |    D    |
---------------------

正如评论中所建议的,(AC|BD)的组合是由一个vpunpcklwd和一个vpunpckhwd给出的。|CD)阶涉及更多且更昂贵的运算。在使用128位矢量实现AVX的平台(例如Zen1)上,这些运算可能特别昂贵。
无论如何,这里是一个使用Intel intrinsics的版本。我也建议在那里搜索说明,而不是在参考手册或随机的互联网网站。

#include <immintrin.h>

void interlace(short* out, const short* in)
{
    /* 1 3 5 7 9 11 13 15 | 17 19 21 23 25 27 29 31 */
    __m256i first = _mm256_loadu_si256((__m256i const*) in);
    /* 2 4 6 8 10 12 14 16 | 18 20 22 24 26 28 30 32 */
    __m256i second = _mm256_loadu_si256((__m256i const*) (in + 16));
    /* 1 2 3 4 5 6 7 8 | 17 18 19 20 21 22 23 24 */
    __m256i ac = _mm256_unpacklo_epi16(first, second);
    /* 9 10 11 12 13 14 15 16 | 25 26 27 28 29 30 31 32 */
    __m256i bd = _mm256_unpackhi_epi16(first, second);
    /* 1 2 3 4 5 6 7 8 | 9 10 11 12 13 14 15 16 */
    __m256i low = _mm256_inserti128_si256(
          ac, _mm256_castsi256_si128(bd), 1);
    /* 17 18 19 20 21 22 23 24 | 25 26 27 28 29 30 31 32 */
    __m256i high = _mm256_permute2x128_si256(
        ac, bd, _MM_SHUFFLE(0, 3, 0, 1));
    _mm256_storeu_si256((__m256i*) out, low);
    _mm256_storeu_si256((__m256i*) (out + 16), high);
}

部件如下所示:

vmovdqu ymm2, YMMWORD PTR [rsi+32]
        vmovdqu ymm0, YMMWORD PTR [rsi]
        vpunpcklwd      ymm1, ymm0, ymm2
        vpunpckhwd      ymm0, ymm0, ymm2
        vinserti128     ymm2, ymm1, xmm0, 0x1
        vperm2i128      ymm1, ymm1, ymm0, 49
        vmovdqu YMMWORD PTR [rdi], ymm2
        vmovdqu YMMWORD PTR [rdi+32], ymm1
        vzeroupper

对于Zen 1来说,vperm2i128是非常昂贵的(每3个周期1个)。用于(CD)部分的两个vextractf128和两个128位存储可能更便宜。或者用提取和插入来替换它。

__m256i high = _mm256_castps_si256(_mm256_insertf128_ps(
          _mm256_castsi256_ps(bd),
          _mm256_extractf128_ps(_mm256_castsi256_ps(ac), 1),
          0));

我不认为这在最近的架构上是必要的。如果有疑问,请咨询uops.info。注意例如,浮点混洗可能比相同大小的整数混洗便宜。

相关问题