我正在尝试确定一种检测英特尔和AMD处理器上AVX和AVX2可用性的有效方法.在阅读英特尔软件开发人员手册第一卷(使用XSAVE功能集管理状态,第310页)时,我更加惊讶地发现它更接近SSE和XSAVE .
英特尔发布了一些用于在启用Is AVX时检测AVX可用性的代码?代码如下所示,并不太痛苦.问题是,Visual Studio是一个痛点,因为我们需要将代码从C/C++文件中移出到X64的ASM文件中.
其他人似乎采取了SIGILL检测AVX可用性的方法.或者他们无意中使用了这种SIGILL方法.例如,请参阅AVX指令上的SIGILL.
我的问题是,使用该SIGILL方法检测AVX可用性是否安全?这里,"安全"表示当CPU和OS支持AVX时,AVX指令不会生成SIGILL; 它会生成一个SIGILL否则.
下面的代码适用于32位计算机,它来自英特尔博客是否启用了AVX?令我担心的是操纵控制寄存器.读取和写入某些X86和ARM控制寄存器有时需要超级用户/管理员权限.这是我更喜欢的原因SIGILL(并避免控制寄存器).
; int isAvxSupported();
isAvxSupported proc
xor eax, eax
cpuid
cmp eax, 1 ; does CPUID support eax = 1?
jb not_supported
mov eax, 1
cpuid
and ecx, 018000000h ; check 27 bit (OS uses XSAVE/XRSTOR)
cmp ecx, 018000000h ; and 28 (AVX supported by CPU)
jne not_supported
xor ecx, ecx ; XFEATURE_ENABLED_MASK/XCR0 register number = 0
xgetbv ; XFEATURE_ENABLED_MASK register is in edx:eax
and eax, 110b
cmp eax, 110b ; check the AVX registers restore at context switch
jne not_supported
supported:
mov eax, 1
ret
not_supported:
xor eax, eax
ret
isAvxSupported endp
Run Code Online (Sandbox Code Playgroud)
首先是一点理论.
要使用AVX指令集,必须满足以下几个条件:
CR4.OSXSAVE[bit 18]必须为1.
此标志由OS设置,以通知处理器它支持xsave扩展.
该xsave扩展是保存AVX状态(只有这样,fxsave不保存ymm寄存器),因此操作系统必须支持他们.
XCR0.SSE[bit 1]和XCR0.AVX[bit 2]必须为1.
这些标志由OS设定发信号通知它支持保存和恢复SSE和AVX状态(通过处理器xsave).
CPUID.1:ECX.AVX[bit 28] = 1
当然,处理器必须首先支持AVX扩展.
所有这些寄存器都是用户模式可读的,但是CR4.
幸运的是,该位CR4.OSXSAVE反映在其中CPUID.1:ECX.OSXSAVE[bit 27],因此所有信息都是用户模式可访问的.不涉及特权指示.
为了使用AVX扩展,必须存在硬件(CPUID.1:ECX.AVX和CPUID.1:ECX.XSAVE)和OS(和)支持.
由于OS 仅在存在硬件支持的情况下发出信号支持,因此测试前者就足够了.
对于AVX扩展,仍建议进行测试,因为即使不支持AVX ,操作系统也可能会设置. CPUID.1:ECX.OSXSAVEXCR0.SSEXCR0.AVXxsaveCPUID.1:ECX.AVXXCR0.AVX
这导致英特尔官方强烈推荐的算法:
这与您发布的完全相同.
捕获异常以检测对AVX扩展的支持也将授予您可以保证捕获的异常是#UD.
例如,通过执行vzeroall唯一可能的异常是#UD和#NM.
第一个只在以下情况下抛出:
如果XCR0 [2:1]≠'11b'.
如果CR4.OSXSAVE [bit 18] = 0.
如果CPUID.01H.ECX.AVX [bit 28] = 0.
如果VEX.vvvv≠1111B.
因此,除非你有一个破坏的汇编程序/编译器,否则它完全等同于开头所述的条件.
后者被抛出作为保存AVX状态的优化,因此,它不会被OS暴露给用户模式程序.
从而追赶SIGILL上vzeroall或类似也会做.