我正在将代码从 SSE 迁移到 AVX。该代码使用
_mm_maskmoveu_si128
,它根据掩码有条件地存储 16 个字节。 32 字节的 AVX 等效项是 _mm256_maskmoveu_si256
,但该指令不存在。
如何有效地模拟它?
MMX/SSE2 字节掩码存储 (
MASKMOVDQU
) 具有 NT 语义,并且在现代 CPU 上不高效。例如Skylake 上具有 6 周期吞吐量的 10 微指令。或者在 Zen 4 上有 75 个 uop,具有 18 个周期延迟。除非掩码为全 1,否则您将拥有一个部分行 NT 存储,它会消耗现代多核 CPU。
如果你可以在不违反多线程正确性的情况下进行非原子加载/
vpblendvb
/存储,那应该可以很好地工作。(这需要AVX2来实现_mm256_blendv_epi8
,不仅仅是AVX,还可能是你正在做的任何事情__m256i
中的单个字节也需要 AVX2。)
唯一好的屏蔽存储(非 NT)是具有 dword 或 qword 粒度的 AVX
vmaskmovps
/pd
(和 AVX2 vpmaskmovd/q
),或具有字节粒度 (vmovdqu8 mem{k}, ymm
) 的AVX-512BW。
AVX 屏蔽存储在 AMD 上非常慢,但 AVX-512 屏蔽存储在 Zen 4 上实际上非常高效(显然是单 uop)。我不知道为什么他们无法实现
vmaskmovps mem, ymm, ymm
的微码来与掩码进行比较并使用它,例如 2 uops 而不是 42。(https://uops.info/)。
AVX1 和 AVX-512 屏蔽存储在 Intel 上都很高效,就像 Skylake 上的 3 uops
vmaskmovps
(端口 0 + 端口 4(存储数据)+ 端口 2/3/7(存储地址)。端口 0 uop 可能是一个 vpmovd2m k, x/ymm
,用于获取双字元素的高位并在只能由微代码使用的内部 k
寄存器中制作 k
掩码。不幸的是,它无法微融合存储地址和存储地址数据微指令也可以在前端,像往常一样,除了存储之外还有微指令指令。