@@ -99,13 +99,16 @@ const (
9999 CLMUL // Carry-less Multiplication
100100 CLZERO // CLZERO instruction supported
101101 CMOV // i686 CMOV
102+ CMPXCHG8 // CMPXCHG8 instruction
102103 CPBOOST // Core Performance Boost
103104 CX16 // CMPXCHG16B Instruction
104105 ENQCMD // Enqueue Command
105106 ERMS // Enhanced REP MOVSB/STOSB
106107 F16C // Half-precision floating-point conversion
107108 FMA3 // Intel FMA 3. Does not imply AVX.
108109 FMA4 // Bulldozer FMA4 functions
110+ FXSR // FXSAVE, FXRESTOR instructions, CR4 bit 9
111+ FXSROPT // FXSAVE/FXRSTOR optimizations
109112 GFNI // Galois Field New Instructions
110113 HLE // Hardware Lock Elision
111114 HTT // Hyperthreading (enabled)
@@ -123,23 +126,27 @@ const (
123126 IBSRIPINVALIDCHK // Instruction Based Sampling Feature (AMD)
124127 INT_WBINVD // WBINVD/WBNOINVD are interruptible.
125128 INVLPGB // NVLPGB and TLBSYNC instruction supported
129+ LAHF // LAHF/SAHF in long mode
126130 LZCNT // LZCNT instruction
127131 MCAOVERFLOW // MCA overflow recovery support.
128132 MCOMMIT // MCOMMIT instruction supported
129133 MMX // standard MMX
130134 MMXEXT // SSE integer functions or AMD MMX ext
135+ MOVBE // MOVBE instruction (big-endian)
131136 MOVDIR64B // Move 64 Bytes as Direct Store
132137 MOVDIRI // Move Doubleword as Direct Store
133138 MPX // Intel MPX (Memory Protection Extensions)
134139 MSRIRC // Instruction Retired Counter MSR available
135140 NX // NX (No-Execute) bit
141+ OSXSAVE // XSAVE enabled by OS
136142 POPCNT // POPCNT instruction
137143 RDPRU // RDPRU instruction supported
138144 RDRAND // RDRAND instruction is available
139145 RDSEED // RDSEED instruction is available
140146 RDTSCP // RDTSCP Instruction
141147 RTM // Restricted Transactional Memory
142148 RTM_ALWAYS_ABORT // Indicates that the loaded microcode is forcing RTM abort.
149+ SCE // SYSENTER and SYSEXIT instructions
143150 SERIALIZE // Serialize Instruction Execution
144151 SGX // Software Guard Extensions
145152 SGXLC // Software Guard Extensions Launch Control
@@ -160,7 +167,9 @@ const (
160167 VPCLMULQDQ // Carry-Less Multiplication Quadword
161168 WAITPKG // TPAUSE, UMONITOR, UMWAIT
162169 WBNOINVD // Write Back and Do Not Invalidate Cache
170+ X87 // FPU
163171 XOP // Bulldozer XOP functions
172+ XSAVE // XSAVE, XRESTOR, XSETBV, XGETBV
164173
165174 // ARM features:
166175 AESARM // AES instructions
@@ -311,6 +320,31 @@ func (c CPUInfo) Has(id FeatureID) bool {
311320 return c .featureSet .inSet (id )
312321}
313322
323+ // https://en.wikipedia.org/wiki/X86-64#Microarchitecture_levels
324+ var level1Features = flagSetWith (CMOV , CMPXCHG8 , X87 , FXSR , MMX , SCE , SSE , SSE2 )
325+ var level2Features = flagSetWith (CMOV , CMPXCHG8 , X87 , FXSR , MMX , SCE , SSE , SSE2 , CX16 , LAHF , POPCNT , SSE3 , SSE4 , SSE42 , SSSE3 )
326+ var level3Features = flagSetWith (CMOV , CMPXCHG8 , X87 , FXSR , MMX , SCE , SSE , SSE2 , CX16 , LAHF , POPCNT , SSE3 , SSE4 , SSE42 , SSSE3 , AVX , AVX2 , BMI1 , BMI2 , F16C , FMA3 , LZCNT , MOVBE , OSXSAVE )
327+ var level4Features = flagSetWith (CMOV , CMPXCHG8 , X87 , FXSR , MMX , SCE , SSE , SSE2 , CX16 , LAHF , POPCNT , SSE3 , SSE4 , SSE42 , SSSE3 , AVX , AVX2 , BMI1 , BMI2 , F16C , FMA3 , LZCNT , MOVBE , OSXSAVE , AVX512F , AVX512BW , AVX512CD , AVX512DQ , AVX512VL )
328+
329+ // X64Level returns the microarchitecture level detected on the CPU.
330+ // If features are lacking or non x64 mode, 0 is returned.
331+ // See https://en.wikipedia.org/wiki/X86-64#Microarchitecture_levels
332+ func (c CPUInfo ) X64Level () int {
333+ if c .featureSet .hasSet (level4Features ) {
334+ return 4
335+ }
336+ if c .featureSet .hasSet (level3Features ) {
337+ return 3
338+ }
339+ if c .featureSet .hasSet (level2Features ) {
340+ return 2
341+ }
342+ if c .featureSet .hasSet (level1Features ) {
343+ return 1
344+ }
345+ return 0
346+ }
347+
314348// Disable will disable one or several features.
315349func (c * CPUInfo ) Disable (ids ... FeatureID ) bool {
316350 for _ , id := range ids {
@@ -497,6 +531,24 @@ func (s *flagSet) or(other flagSet) {
497531 }
498532}
499533
534+ // hasSet returns whether all features are present.
535+ func (s flagSet ) hasSet (other flagSet ) bool {
536+ for i , v := range other [:] {
537+ if s [i ]& v != v {
538+ return false
539+ }
540+ }
541+ return true
542+ }
543+
544+ func flagSetWith (feat ... FeatureID ) flagSet {
545+ var res flagSet
546+ for _ , f := range feat {
547+ res .set (f )
548+ }
549+ return res
550+ }
551+
500552// ParseFeature will parse the string and return the ID of the matching feature.
501553// Will return UNKNOWN if not found.
502554func ParseFeature (s string ) FeatureID {
@@ -706,6 +758,7 @@ func (c *CPUInfo) cacheSize() {
706758 if maxFunctionID () < 4 {
707759 return
708760 }
761+ c .Cache .L1I , c .Cache .L1D , c .Cache .L2 , c .Cache .L3 = 0 , 0 , 0 , 0
709762 for i := uint32 (0 ); ; i ++ {
710763 eax , ebx , ecx , _ := cpuidex (4 , i )
711764 cacheType := eax & 15
@@ -861,9 +914,14 @@ func support() flagSet {
861914 family , model := familyModel ()
862915
863916 _ , _ , c , d := cpuid (1 )
917+ fs .setIf ((d & (1 << 0 )) != 0 , X87 )
918+ fs .setIf ((d & (1 << 8 )) != 0 , CMPXCHG8 )
919+ fs .setIf ((d & (1 << 11 )) != 0 , SCE )
864920 fs .setIf ((d & (1 << 15 )) != 0 , CMOV )
921+ fs .setIf ((d & (1 << 22 )) != 0 , MMXEXT )
865922 fs .setIf ((d & (1 << 23 )) != 0 , MMX )
866- fs .setIf ((d & (1 << 25 )) != 0 , MMXEXT )
923+ fs .setIf ((d & (1 << 24 )) != 0 , FXSR )
924+ fs .setIf ((d & (1 << 25 )) != 0 , FXSROPT )
867925 fs .setIf ((d & (1 << 25 )) != 0 , SSE )
868926 fs .setIf ((d & (1 << 26 )) != 0 , SSE2 )
869927 fs .setIf ((c & 1 ) != 0 , SSE3 )
@@ -873,6 +931,7 @@ func support() flagSet {
873931 fs .setIf ((c & 0x00100000 ) != 0 , SSE42 )
874932 fs .setIf ((c & (1 << 25 )) != 0 , AESNI )
875933 fs .setIf ((c & (1 << 1 )) != 0 , CLMUL )
934+ fs .setIf (c & (1 << 22 ) != 0 , MOVBE )
876935 fs .setIf (c & (1 << 23 ) != 0 , POPCNT )
877936 fs .setIf (c & (1 << 30 ) != 0 , RDRAND )
878937
@@ -888,6 +947,8 @@ func support() flagSet {
888947 if vend == AMD && (d & (1 << 28 )) != 0 && mfi >= 4 {
889948 fs .setIf (threadsPerCore () > 1 , HTT )
890949 }
950+ fs .setIf (c & 1 << 26 != 0 , XSAVE )
951+ fs .setIf (c & 1 << 27 != 0 , OSXSAVE )
891952 // Check XGETBV/XSAVE (26), OXSAVE (27) and AVX (28) bits
892953 const avxCheck = 1 << 26 | 1 << 27 | 1 << 28
893954 if c & avxCheck == avxCheck {
@@ -992,6 +1053,7 @@ func support() flagSet {
9921053 fs .set (LZCNT )
9931054 fs .set (POPCNT )
9941055 }
1056+ fs .setIf ((c & (1 << 0 )) != 0 , LAHF )
9951057 fs .setIf ((c & (1 << 10 )) != 0 , IBS )
9961058 fs .setIf ((d & (1 << 31 )) != 0 , AMD3DNOW )
9971059 fs .setIf ((d & (1 << 30 )) != 0 , AMD3DNOWEXT )
0 commit comments