我有一些现有的 avx/sse 掩码,是我用旧方法得到的:
auto mask_sse = _mm_cmplt_ps(a, b);
auto mask_avx = _mm_cmp_ps(a, b, 17);
在某些情况下,当将旧的 avx 代码与新的 avx512 代码混合时,我想将这些旧样式的掩码转换为新的 avx512 __mmask4
或 __mmask8
类型。
我试过这个:
auto mask_avx512 = _mm_cmp_ps_mask(sse_mask, _mm_setzero_ps(), 25/*nge unordered quiet*/);
它似乎适用于比较的普通旧输出,但我不认为它会正确捕获可能与 sse4.1 _mm_blendv_ps
一起使用的正 NAN。
还有很好的旧_mm_movemask_ps
,但看起来它把掩码一直放在通用寄存器中,我需要用 _cvtu32_mask8
链接它> 将其拉回专用掩码寄存器之一。
是否有更简洁的方法直接将符号位从旧式掩码中拉出到 k 个寄存器之一?
示例代码:
这是一个按照我上面提到的第一种方式进行掩码转换的示例程序
#include "x86intrin.h"
#include <cassert>
#include <cstdio>
int main()
{
auto a = _mm_set_ps(-1, 0, 1, 2);
auto c = _mm_set_ps(3, 4, 5, 6);
auto sse_mask = _mm_cmplt_ps(a, _mm_setzero_ps());
auto avx512_mask = _mm_cmp_ps_mask(sse_mask, _mm_setzero_ps(), 25);
alignas(16) float v1[4];
alignas(16) float v2[4];
_mm_store_ps(v1, _mm_blendv_ps(a, c, sse_mask));
_mm_store_ps(v2, _mm_mask_blend_ps(avx512_mask, a, c));
assert(v1[0] == v2[0]);
assert(v1[1] == v2[1]);
assert(v1[2] == v2[2]);
assert(v1[3] == v2[3]);
return 0;
}
最佳答案
首先使用 AVX-512 比较内在函数来获得 AVX-512 掩码(如 _mm_cmp_ps_mask
);这将比先比较一个 vector 然后再转换它要高效得多,除非编译器为您优化掉这种低效率。 (考虑使用像 Agner Fog's VCL 这样的包装库来尝试抽象出差异。VCL 许可证最近从 GPL 更改为 Apache。)
但如果您真的需要这个(例如,作为完成优化之前的权宜之计),您不需要 FP 比较。 _mm_cmp_ps
在 C 中产生一个 __m128
结果,但它真的不是 float 1的 vector 。它是全一位/全零位。你只想要这些位,所以你正在寻找 AVX-512 等效于 vmovmskps
, 但进入 k
注册而不是 GP 整数。即 VPMOVD2M k, x/y/zmm
对于 32 位源元素。
__m128 cmpvec = _mm_cmplt_ps(v, _mm_setzero_ps() );
__mmask8 cmpmask = _mm_movepi32_mask( _mm_castps_si128(cmpvec) ); // <----
// equivalent to comparing into a mask in the first place:
__mmask8 cmpmask = _mm_cmplt_ps_mask(v, _mm_setzero_ps(), _CMP_LT_OQ);
// equivalent to (if I got this right)
__mmask8 cmpmask = _mm_fpclass_ps_mask(v, 0x40 | 0x10); // negative | negative_inf
https://uops.info/现在正在关闭,否则我会检查 VPMOVD2M 与 VCMPPS 的延迟和执行端口到掩码(对于 UNORD 谓词)与 VFPCLASSPS。
脚注 1:您可以使用 AVX-512 vfpclassps
进入面具,甚至与 vcmpps
进行比较像 UNORD 这样的谓词来检测 NAN 与否。但我认为这些速度较慢。
I would need to chain it with a
_cvtu32_mask8
to pull it back into one of the dedicated mask registers.
编译器当前做事的方式,__mmask8
只是 unsigned char
的类型定义, 和 __mmask16
是unsigned short
.它们可以在没有内在函数的情况下自由转换,无论好坏。但在 asm 中,它需要一个 kmovb k1, eax
将数据从 GP reg 获取到 k mask reg 的指令,并且该指令只能在当前 CPU 的端口 5 上运行。
关于c++ - 从 avx/sse 掩码到 avx512 掩码的 "correct"方法是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66493835/