我有一些依赖于AVX的代码。
在同一代码库中,我还使用了TZCNT
.
后者是BMI1的一部分。我知道我可以使用CPUID测试此指令,但我很懒,所以我没有实际实现它。
为了测试支持,我只需执行一个AVX指令。如果我得到一个#UD
未定义指令异常,我就知道CPU不支持AVX。
然而,tzcnt
与bsf
(或bsr
- 我总是忘记哪个是哪个)向后兼容,因此不会触发异常。
如果我支持AVX
,那是否意味着我支持BMI1
?
录音记录,我现在测试的CPU上没有AVX2。
Intel AMD Year
---------------------------------------------------
AVX Sandy Bridge Bulldozer 2011
---------------------------------------------------
BMI1 Haswell Piledriver/Jaguar 2013
---------------------------------------------------
ABM Barcelona 2007
Haswell 2013
---------------------------------------------------
AVX2 Haswell 2013
Carrizo 2015
Ryzen 2017
---------------------------------------------------
BMI2 Haswell 2013
Excavator 2015
Ryzen 2017
大多数处理器都支持这两种指令,但AVX比BMI1早两年。
此外,tzcnt
和bsf
在标志方面有不同的语义。
如果您想强制引发#UD
异常,可以使用andn
。
如果您想使用CPUID:
BMI1 -> CPUID.(EAX=07H, ECX=0H):EBX.BMI1[bit 3]
(ANDN, BEXTR, BLSI, BLSMSK, BLSR, TZCNT)
BMI2 -> CPUID.(EAX=07H, ECX=0H):EBX.BMI2[bit 8]
(BZHI, MULX, PDEP, PEXT, RORX, SARX, SHLX, SHRX)
LZCNT -> CPUID.(EAX=80000001H) ECX.LZCNT[bit 5]
POPCNT -> CPUID.(EAX=01H) :ECX.POPCNT [Bit 23]
popcnt
,它通常也会支持。CPUID.(EAX=07H, ECX=0H):EBX.BMI1[位 3]
BMI2 (BZHI, MULX, PDEP, PEXT, RORX, SARX, SHLX, SHRX) -> CPUID.(EAX=07H, ECX=0H):EBX.BMI2[位 8]
LZCNT -> CPUID.EAX=80000001H:ECX.LZCNT[位 5]
。这是英特尔术语:CPUID.EAX=80000001H:ECX.LZCNT[位 5]
表示 AMD 处理器上的 ABM(即 popcnt
+ lzcnt
)(因为 popcnt
有自己的 CPUID 位,而 ABM -> popcnt
而不是反过来)。 - Margaret Bloomandn
是否在所有地方都会陷入。毕竟,VEX前缀只是lds,我不确定所有旧的CPU在看到具有无效操作数组合的lds时是否会引发异常。但是,在64位模式下,这不应该是一个问题,因为lds和les是非法的。 - fuzpopcnt
但不设置CPUID功能位?在我的第一代Core2(Conroe / Merom:SSSE3但不是SSE4.1)上会出现故障。 - Peter Cordes
tzcnt
(rep bsf
)。在AMD CPU上,tzcnt
比bsf
快得多。在Intel Skylake(及以后?)上,它避免了bsf
对只写目标寄存器的错误依赖。 (popcnt
仍然具有SKL上的错误依赖,就像早期Intel CPU上的lz/tzcnt
一样。) - Peter Cordes