我正在尝试确定一种检测英特尔和AMD处理器上AVX和AVX2可用性的有效方法 . 在阅读英特尔软件开发人员手册第一卷(使用XSAVE功能集管理状态,第310页)时,我更加惊讶地发现它更接近SSE和XSAVE .
英特尔在Is AVX enabled?发布了一些用于检测AVX可用性的代码 . 代码如下所示,并且不会太痛苦 . 问题是,Visual Studio是一个痛点,因为我们需要将代码从C / C文件中移出到X64的ASM文件中 .
其他人似乎采用 SIGILL
方法来检测AVX可用性 . 或者他们无意中使用了 SIGILL
方法 . 例如,参见SIGILL on AVX instruction .
我的问题是,使用 SIGILL
方法检测AVX可用性是否安全?这里,"safe"表示当CPU和OS支持AVX时,AVX指令不会生成 SIGILL
;否则它将生成一个 SIGILL
.
下面的代码适用于32位机器,它来自英特尔博客Is AVX enabled?令我担心的是操纵控制寄存器 . 读取和写入某些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
1 回答
首先是一点理论 .
要使用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(CPUID.1:ECX.OSXSAVE
,XCR0.SSE
和XCR0.AVX
) .由于操作系统仅在存在硬件支持的情况下表示支持
xsave
,因此测试前者就足够了 .对于AVX扩展,仍建议测试
CPUID.1:ECX.AVX
,因为即使不支持AVX,操作系统也可能设置XCR0.AVX
.这导致英特尔官方强烈推荐的算法:
这与您发布的完全相同 .
捕获异常以检测对AVX扩展的支持也将授予您可以保证捕获的异常是#UD .
例如,通过执行
vzeroall
,唯一可能的例外是#UD和#NM .第一个只在以下情况下抛出:
因此,除非你有一个破坏的汇编程序/编译器,否则它完全等同于开头所述的条件 .
后者被抛出作为保存AVX状态的优化,因此,它不会被OS暴露给用户模式程序 .
从而在
vzeroall
或类似的地方捕捉SIGILL
也可以 .