SSE/AVX

时至今日,SSE 已经成为 x86 系统中默认开启的功能。SSE4 中,定义了 128 位寄存器及对应的 SIMD 指令,这成为了后续 AVX 继续设计的基础。 AVX2 比 SSE 略新,一般需要指定架构才编译,不过实际上在大部分的 x86 CPU 中都启用。AVX 中定义了 256 位的寄存器,但是这些寄存器通常是作为两个同样的 128 位寄存器(lane)使用,必须使用vperm或是vpack等少数指令才能跨越 128 位边界,这是因为在不跨越 128 位边界的情况下,可以用两个 128 位的单元重叠地处理 256 位数据(double pumping),在同样的计算单元规模下,性能并不差,只是寄存器上下半间可能有一定延迟。而跨越边界的指令由 128 位单元处理可能非常缓慢,可能要几十个周期。 而 AVX512 是一组特性的集合,包括多个小的扩展,比如最基本的 AVX512F(Foundation)拓展了 512 位的寄存器及相关运算,并且把向量寄存器数量从 16 个拓展到 32 个。更加重要的是,AVX2 后续已经不再更新,AVX512 实际上是 AVX3-AVX9,如 AVX2 只定义了按偏移量读取数组的vgather系列指令,但没有定义对应的写入指令,这由 AVX512F 中的vpscatter系列指令补全。后续 AI 中常用的 16 位浮点,如半精度bfloat16 都包括在 AVX512 中。由于 AVX512 并不是一个单独的拓展,包括了十几个小的拓展,进行指令集判断时非常不便,因此英特尔在去年又推出了 AVX10。AVX10 最主要的目标是简化 CPUID 的判断,即支持 AVX10 代表这个 CPU 支持大部分常用的 AVX512 拓展。AVX10 的另一个目的是支持 256 位的 AVX512,即支持 AVX512 中加入的各种新指令以及 32 个向量寄存器,只是大小限制在 256 位,否则 不支持 AVX512 的 E 核只能使用 AVX2

虽然 AVX512 的 512 位运算推出很早,但是由于 AVX512 指令能耗过高,对应指令很长一段时间内都需要由 CPU 降频运行,速度很可能不如 AVX2。直到最近的 Zen4、Zen5、Sunny Cove 才改变了现状,见:Zen4’s AVX512 TeardownZen5’s AVX512 Teardown + More…Ice Lake AVX-512 Downclocking

指令相关的资料,包括所用的头文件和 C 函数名,可以在 Intel® Intrinsics Guide 查看。

NEON

ARM 在 SIMD 方面则统一很多,只有一个 NEON 扩展,提供 128 位向量及浮点运算。NEON 的指令数量虽然不多,但设计相比 SSE/AVX 要整齐不少,比如在 swizzle 方面有包括vldN/vstN/vrev/vext/vtrn/vzip/vuzip/vtbl/vtbx等多个指令,参考:Permutation - Neon instructions

NEON 指令相关信息可以在 Intrinsics - Arm Developer 查看,注意里面的 Helium 是针对 M 系列 CPU 提出的 SIMD,又叫 MVE,而 SVE 目前在消费级产品上没有应用。NEON 所有的指令都位于#include <arm_neon.h>中。

宏定义

对于 GCC,使用下列命令获取架构相关的宏定义。

gcc -march=native -dM -E - < /dev/null | egrep "SSE|AVX|ARM" | sort

MSVC 的宏定义则直接在官网查看:Microsoft-specific predefined macros