我计划实现 SIMD 扩展的运行时检测。是不是如果我发现处理器支持AVX2,就一定也支持SSE4.2和AVX?
支持最新的 Intel SIMD ISA 扩展意味着支持以前的 SIMD。
AVX2 绝对意味着 AVX1。
我认为 AVX1 意味着所有 SSE / SSE2 / SSE3 / SSSE3 / SSE4.1 / SSE4.2 功能位也必须在 CPUID 中设置。如果没有正式保证,很多都会做出这样的假设,而违反该假设的 CPU 可能无法在商业上实现一般用途。
请注意,
popcnt
有自己的功能位,因此理论上,您可以拥有带有AVX2和SSE4.2的CPU,但不是popcnt
,但很多东西将SSE4.2视为暗示popcnt
。所以更像是您可以在没有 SSE4.2 的情况下宣传对 popcnt
的支持。
理论上,您可以使用 AVX 制作 CPU(或虚拟机),但它不接受 SSE4.2 指令的非 VEX 传统 SSE 编码,如
pcmpistri
,但我认为您会违反英特尔的保证关于 AVX 功能位的含义。不确定这是否正式写在手册中,但大多数软件都会假设这一点。 (SSE1 和 SSE2 是 x86-64 的基准,但不适用于 32 位模式。)
但是 AVX1 确实 意味着支持 all SSE4.2 和早期 SIMD 指令的 VEX 编码,例如
vpcmpistri
或 vminss
gcc -mavx2
绝对意味着 AVX1 和以前的扩展,(-Q --help=target
可见),但只会发出使用 VEX 编码的代码。不过,它将定义 __SSE4_2__
宏等,因此 GCC 确实将 AVX2 视为暗示早期的 SSE 扩展和 popcnt
,但不包括 FMA、AES-NI 或 PCLMUL。即使对于 GCC 来说,这些也是单独的功能。
(实际上,您应该使用
gcc -march=native
或 gcc -march=znver1
或其他任何工具来启用 CPU 具有的所有功能,和 为其设置调整选项。不仅仅是 -mavx2 -mfma
,这会使调整设置处于不良默认值,例如拆分每个可能未对齐的 256 位加载/存储到 128 位的一半中。)
(请注意,MSVC 没有那么多 SIMD ISA 检测宏;它有一个用于 AVX 的宏,但不适用于所有早期的 SSE* 扩展。MSVC 的模型是围绕程序将执行运行时 CPU 检测而不是编译的假设而设计的对于本地计算机。虽然 MSVC 现在确实有 AVX 和 AVX2 选项可以将它们用作基线。)
请注意,AVX512 有点打破传统。 AVX512F 意味着支持 AVX2 及其之前的所有内容,但除此之外,AVX512DQ 不会出现在 AVX512ER“之前”或“之后”。 (理论上)你可以选择其中之一,也可以两者都拥有,或者两者都不拥有。 (实际上,Skylake-X/Cannonlake/等与 Xeon Phi(Knight's Landing / Knight's Mill)只有一点重叠,超出了 AVX512F。https://en.wikipedia.org/wiki/AVX-512#CPUs_with_AVX -512
如果我们设置编译器选项
-mavx2
,当我们使用 AVX 或 SSE 内在函数时,GCC 不会给出错误。因此 GCC 假设 AVX2 标志的存在足以运行 AVX 和 SSE 代码。当然,这并不能保证有人不会创建带有 AVX2 且没有 SSE 的 CPU。
原则上,CPU 可以只支持 AVX2,而不支持任何 SSE4 指令(这并不像听起来那么愚蠢!)。但实际上,如果它支持 AVX2,它也支持 SSE4。