Dan*_*iel 3 intrinsics avx avx512
AVX 具有将 16 位和 32 位整数插入和提取到__m256i向量中的指令:_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)有关的:
vpblendw重复两条车道的混合控制,不像vpblendd)。这并没有利用 AVX512 来进行例如合并掩码广播。AVX具有指示用于插入和提取16个32位整数到__m256i载体:
不,它没有,_mm256_insert_epi16并且epi32内在函数是“假的”;它们必须用多条指令进行模拟,同样的方式_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 版本在 a__m256i上不可用,因为它将高 128 位清零。请参阅使用ymm寄存器为“记忆样”存储位置(可以使用传统SSE编码插入到低一个YMM 128位pinsrd xmm, r/m32, imm,但这是灾难性的缓慢上的Haswell和冰湖,因为怎样的SSE / AVX过渡处罚在那里工作。但在 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 输入混洗vpermt2d,您可以使用这样的方式将一个元素从一个 x/y/zmm 的底部插入到另一个向量中的任何位置(将所有其余的来自另一个向量的目标元素作为源)。
但这里最有用的是掩码广播: uops.info 确认这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);
}
Run Code Online (Sandbox Code Playgroud)
在 Godbolt上编译成这个 asm:
# 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
Run Code Online (Sandbox Code Playgroud)
(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)。一个有用的 shuffle 是valignd按 dword 元素移动或旋转,让您有效地将任何元素放到向量的底部,而无需向量控制。 https://www.felixcloutier.com/x86/valignd:valignq
| 归档时间: |
|
| 查看次数: |
720 次 |
| 最近记录: |