我一直在尝试在支持 AVX512 的机器和之前针对 AVX2 优化的代码上使用_mm256_popcnt_epi64。
不幸的是,我遇到了找不到该功能的问题。 但是,可以找到相应的__m512i
等效项。 是否弃用了__m256i
函数?
_mm512_popcnt_epi64
是AVX512-VPOPCNTDQ的一部分。 256 位和 128 位版本还要求AVX512VL使用具有 128 或 256 位矢量的 AVX512 指令。
主流的AVX512CPU都有AVX512-VL。 Xeon Phi CPU 没有 AVX512-VL。
(_mm512_popcnt_epi8
和epi16也是Ice Lake的新功能,作为AVX512-BITALG的一部分(
也许您忘记启用必要的编译器选项(例如 GCC-march=native
以启用您正在编译的计算机可以执行的所有操作(,或者您正在为不具有这两个功能的目标进行编译。 如果是这样,那么编译器将没有将_m256_popcnt_epi64
定义为内部函数,因此在 C 中,它将承担其和未声明的函数并发出对它的调用。 (当然,在链接时不会找到。 和/或它会警告或错误(C 或 C++(找不到原型。
目前很少有CPU具有AVX512-VPOPCNTDQ(维基百科AVX512功能与CPU矩阵(:
Knight's Mill(最後一代Xeon Phi(:只有AVX512-VPOPCNTDQ,沒有AVX512VL,也沒有BITALG。 因此,只有
__m512i
版本可用于gcc -O3 -march=knm
. 您绝对应该在至强 Phi 上使用 512 位向量,除非数据布局非常适合 256 位并且需要额外的洗牌才能达到 512 位。 但请注意,对于某些没有 512 位版本的 AVX/AVX2 指令来说,它很慢,例如元素小于 32 位的随机播放。 (无 AVX512 带宽(Ice Lake/Tiger Lake:具有 AVX512 VPOPCNTDQ、BITALG 和 AVX512 VL,因此在针对此目标微架构进行编译时支持
_mm256_popcnt_epi64
和epi8
,例如gcc -O3 -march=icelake-client
. (假设编译器的标头正确(。GCC8.3及更早版本有一个错误,即
-march=icelake-client
/icelake-server
无法启用-mavx512vpopcntdq
。 (GCC7不知道-march=icelake-client
(。它在GCC8.4中已修复,因此要么升级到最新的GCC8,要么更好地升级到最新的稳定GCC;再开发几年通常应该有助于GCC使用新的ISA扩展(如AVX-512(制作更好的代码,尤其是掩码寄存器。 或者只是手动使用-march=icelake-client -mavx512vpopcntdq
;这确实有效:https://godbolt.org/z/a7bhcjdhr
在Ice Lake 上选择 256 位矢量与 512 位矢量是一种权衡,就像在 Skylake-x 上一样:当 512 位矢量 uop 运行时,端口 1 上的矢量 ALU 不会被使用。 并且最大涡轮时钟速度可能会降低。 降低 CPU 频率的 SIMD 指令。 因此,如果您没有从更宽的矢量中获得太多加速(例如,由于内存瓶颈,或者您的 SIMD 循环只是较大程序的一小部分(,则在一个循环中使用 512 位矢量可能会损害整体性能。
但请注意,Icelake 客户端 CPU 不会受到太大影响,我不确定vpopcnt
指令是否算作"沉重",也许不会减少最大涡轮增压,如果有的话,在客户端 CPU 上。 大多数整数 SIMD 指令不计算在内。 请参阅关于 LLVM [X86] 在 Ice/Rocket/TigerLake 上首选 512 位向量的讨论 (PR48336(。 但是,端口 1 的矢量 ALU 部分在 512 位 uop 运行时仍会关闭。
其他 CPU 根本不支持硬件 SIMD popcnt,也没有可用的_mm512_popcnt_epi64
形式。
即使您只有 AVX2,根本没有 AVX512,SIMD popcnt 也优于标量popcnt
,胜过具有快速vpshufb
(_mm256_shuffle_epi8
(的现代 CPU 上的非微型阵列。https://github.com/WojciechMula/sse-popcount/具有 AVX2 和 AVX512 版本,它们使用vpternlogd
进行哈雷海豹累积,以减少用于弹出计数的 SIMD LUT 查找量。
同样在堆栈溢出上,使用 AVX-512 或 AVX-2 对大数据进行 1 位(人口计数(计数,显示几年前从该存储库复制的一些代码。
如果您需要单独对单独的元素进行计数,只需使用标准解包进行vpshufb
,并根据零向量vpsadbw
,以将 hsum 成 64 位 qword 块。
如果需要位置弹出计数(每个位位置的单独总和(,请参阅 https://github.com/mklarqvist/positional-popcount。