到目前为止,我已经设法发现:
- SSE 和 SSE2 对于 Windows 8 及更高版本是强制性的(当然对于任何 64 位操作系统)
- AVX 仅受 Windows 7 SP1 或更高版本支持
在 Windows 上使用 SSE3、SSSE3、SSE4.1、SSE 4.2、AVX2 和 AVX-512 是否有任何注意事项?
一些澄清:如果我使用来自 SSE/AVX 集合之一的指令,我需要它来确定我的程序将在哪些操作系统上运行。
引入新架构状态的扩展需要特殊的操作系统支持,因为操作系统必须在上下文切换上保存/恢复更多数据。因此,从操作系统的角度来看,如果操作系统支持 SSE,那么让用户空间代码运行 SSSE3 指令不需要做任何额外的事情。
SSE、AVX 和 AVX512 是引入新架构状态的扩展。
xmm
regs(以及MXCSR
用于舍入模式和 FP 异常状态)ymm
(其中下半部分是旧的xmm
regs)。zmm
(扩展了x/ymm
regs),并且还在 64 位模式下将矢量 regs 的数量增加了一倍:zmm0-zmm31。x/y/zmm16..31 只能通过向量指令的 AVX-512 编码(EVEX 前缀)访问,因此有趣的是可以在不需要的vzeroupper
情况下使用,并且不受它的影响。k0..k7
64 位掩码寄存器(或在 Xeon Phi 中没有 AVX-512BW 的 16 位)在 AVX-512 中也是新的。您可以使用 CPUID 指令以通常的方式检查 CPU 对 SSE 或 AVX 的支持。
为了防止在多任务操作系统上使用新扩展时出现静默数据损坏,该扩展不会在上下文切换时保存/恢复新架构状态,如果操作系统没有在一个控制寄存器。因此,向量扩展在不知道保存/恢复该扩展的必要状态的操作系统上“不起作用”。
对于 SSE,可能没有任何干净的独立于操作系统的方法来检测操作系统已承诺通过设置等位在上下文切换上保存/恢复 SSE 状态CR4.OSFXSR
,CR4.OSXMMEXCPT
因为即使读取控制寄存器也是特权,并且没有 CPUID反映设置的位。SSE 支持如此广泛,以至于您必须使用非常古老的版本(或自制)操作系统才能成为问题。
对于 AVX,我们不需要操作系统支持来检测 AVX 是否可用(由硬件支持并由操作系统启用):用户空间可以运行xgetbv
并检查启用功能标志以查看操作系统是否已启用 AVX 指令运行没有过错。
- 使用 .验证操作系统是否支持 XGETBV
CPUID.1:ECX.OSXSAVE bit 27 = 1
。- 同时,验证
CPUID.1:ECX bit 28=1
(支持 Intel AVX)和/或位 25=1(支持 AES)... (以及 FMA、AES 和 PCLMULQDQ 的其他位)- 发出
XGETBV
,并验证第 1 位和第 2 位的功能启用掩码是11b
(操作系统启用的 XMM 状态和 YMM 状态)。
调用 OS 提供的函数来检测 OS 支持可能更容易,而不是使用内联 asm 或功能检测库来完成所有这些工作。例如,Win7SP1 引入GetEnabledXStateFeatures
了对 AVX CPU 的支持。(在没有 SSE 的 CPU 上运行 Win7SP1 是不太可能或不可能的,因此对于 SSE,您只需检查 CPUID 和操作系统版本即可。)
这也被理解为操作系统的上下文切换将正确保存/恢复完整状态的承诺,当然,错误、恶意或深奥的操作系统(可能是协作多任务?)可能会有所不同。对于包括 Windows 在内的主流操作系统,这确实意味着 YMM 寄存器将像您期望的那样保持它们的值。
AVX512 也是如此:您可以检查指令集的 CPUID 功能位,并检查操作系统是否已承诺通过启用 XSETBV 中的正确位来管理上下文切换时的新架构状态。(所以你应该检查 XGETBV)。检查 XGETBV 结果并且 0xE6 等于 0xE6。