gpt4 book ai didi

intrinsics - 如何使用 AVX-512 实现 16 位和 32 位整数插入和提取操作?

转载 作者:行者123 更新时间:2023-12-01 23:40:34 28 4
gpt4 key购买 nike

AVX 有在 __m256i 中插入和提取 16 位和 32 位整数的指令向量:_mm256_insert_epi16 , _mm256_insert_epi32 , _mm256_extract_epi16 , _mm256_extract_epi32 .

但是,AVX-512 似乎没有等效的说明。为 __m512i 实现这些方法的适当方法是什么?向量? IE。

  • __m512i _mm512_insert_epi16(__m512i a, __int16 i, int index)
  • __m512i _mm512_insert_epi32(__m512i a, __int32 i, int index)
  • int _mm512_extract_epi16(__m512i a, int index)
  • int _mm512_extract_epi32(__m512i a, int index)
  • 最佳答案

    有关的:

  • How can I write a QuadWord from AVX512 register zmm26 to the rax register? - 其中大部分也适用于提取 32 位和 16 位元素。
  • Move an int64_t to the high quadwords of an AVX2 __m256i vector显示插入,而且其中大部分应该适用于 32 位元素,并且可能适用于 16 位元素。 (尽管 vpblendw 重复两条车道的混合控制,与 vpblendd 不同)。这并没有利用 AVX512 例如合并掩码广播。
  • Loading an xmm from GP regs展示了 AVX512 如何使用合并掩码广播。但我没有费心为那里的 asm 编写内在函数。

  • AVX has instructions for inserting and extracting 16 and 32 bit integers into __m256i vectors:


    不,不是, _mm256_insert_epi16epi32内在函数是“假的” ;他们必须用多条指令来模拟,同样的方式 _mm_set_epi32(a,b,c,d)不是任何单个指令的内在指令。
    IDK 为什么英特尔选择为 AVX1/2 而不是 AVX512 版本提供它们;也许他们后来意识到他们不应该为 AVX2 提供它们,以避免在假设这些内在函数只花费一次洗牌的情况下愚弄人们编写低效的代码。但是他们不能在不破坏现有代码的情况下删除现有的。
    vpinsrd ymm_dst, ymm_src, r/m32, imm8 (或 ZMM)不幸的是不存在 ,只有xmm。 ( https://www.felixcloutier.com/x86/pinsrb:pinsrd:pinsrq )。 XMM 版本在 __m256i 上无法使用因为它将高 128 位清零。见 Using ymm registers as a "memory-like" storage location (您可以使用 pinsrd xmm, r/m32, imm 的传统 SSE 编码插入 YMM 的低 128 位,但由于 SSE/AVX transition penalties 在那里的工作方式,这在 Haswell 和 Ice Lake 上的速度非常慢。但在 Skylake 或 Ryzen 上很好。不过,编译器永远不会发出那个。) _mm256_insert_epi32可能会使用 AVX2 编译为广播负载和 vpblendd从内存中插入一个双字。或者更糟的是,对于寄存器中的整数,编译器可能 vmovd将其发送到 xmm reg,将其广播到 YMM,然后混合。 (就像我在 Move an int64_t to the high quadwords of an AVX2 __m256i vector 中展示的那样)

    “适当”的实现取决于周围的代码。
    如果要插入的元素超过 1 个,则可能需要在插入前将它们混洗在一起。或者甚至考虑向量存储,多个标量存储,然后向量重新加载,尽管存储转发停顿。或者,如果延迟关键路径通过向量而不是标量,则标量存储/向量重新加载以提供混合。如果您有很多小标量元素,可能值得。

    然而,对于单个插入 AVX512F 实际上有一些不错的功能 :它有 2-input shuffle,如 vpermt2d您可以使用它从一个 x/y/zmm 的底部插入一个元素到另一个向量中的任何位置(将另一个向量中的所有其余目标元素作为源)。
    但这里最有用的是屏蔽广播: uops.info confirms那个 VPBROADCASTW zmm0{k1}, eax是一个单 uop 指令,从向量到向量(用于合并)以及从掩码到向量有 3 个周期的延迟。并且 <= 从 eax 到合并结果的 5 个周期延迟。唯一的问题是设置掩码,但希望可以将其从循环中提升出来,以获得不变的插入位置。
    #include <immintrin.h>
    #include <stdint.h>
    __m512i _mm512_insert32(__m512i target, uint32_t x, const int pos)
    {
    return _mm512_mask_set1_epi32(target, 1UL<<pos, x);
    }
    编译 on Godbolt到这个汇编:
    # gcc8.3 -O3 -march=skylake-avx512
    _mm512_insert32(long long __vector(8), unsigned int, int):
    mov eax, 1
    shlx eax, eax, esi
    kmovw k1, eax # mask = 1<<pos
    vpbroadcastd zmm0{k1}, edi
    ret
    (gcc9 无缘无故地浪费了一条额外的指令来复制 ESI)。
    使用编译时间常量 pos你会得到类似 mov eax,2 的代码/ kmovw k1, eax ;蒙面广播可能仍然是最好的选择。
    这适用于 8、16、32 或 64 位元素 . 8 和 16 当然需要 AVX512BW 用于 vpbroadcastb/w 窄广播,而 32 和 64 只需要 AVX512F。

    提炼:
    只需将您想要的元素移动到 __m512i 的底部您可以在哪里使用 _mm_cvtsi128_si32 . (在 _mm512_castsi512_si128 之后)。一个有用的洗牌是 valignd按 dword 元素移动或旋转,让您有效地将任何元素置于向量的底部,而无需向量控制。 https://www.felixcloutier.com/x86/valignd:valignq

    关于intrinsics - 如何使用 AVX-512 实现 16 位和 32 位整数插入和提取操作?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58303958/

    28 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com