Wie prüfe ich, ob eine CPU den SSE3-Befehlssatz unterstützt?

Ist der folgende Code gültig, um zu prüfen, ob eine CPU den SSE3-Befehlssatz unterstützt?

Die Verwendung der function IsProcessorFeaturePresent() funktioniert unter Windows XP anscheinend nicht (siehe http://msdn.microsoft.com/en-us/library/ms724482(v=vs.85).aspx ).

 bool CheckSSE3() { int CPUInfo[4] = {-1}; //-- Get number of valid info ids __cpuid(CPUInfo, 0); int nIds = CPUInfo[0]; //-- Get info for id "1" if (nIds >= 1) { __cpuid(CPUInfo, 1); bool bSSE3NewInstructions = (CPUInfo[2] & 0x1) || false; return bSSE3NewInstructions; } return false; } 

Solutions Collecting From Web of "Wie prüfe ich, ob eine CPU den SSE3-Befehlssatz unterstützt?"

Ich habe eine GitHub-Repro erstellt, die die CPU- und Betriebssystemunterstützung für alle wichtigen x86-ISA-Erweiterungen erkennt : https://github.com/Mysticial/FeatureDetector

Hier ist eine kürzere Version:


Zuerst müssen Sie auf die CPUID-statement zugreifen:

 #ifdef _WIN32 // Windows #define cpuid(info, x) __cpuidex(info, x, 0) #else // GCC Intrinsics #include  void cpuid(int info[4], int InfoType){ __cpuid_count(InfoType, 0, info[0], info[1], info[2], info[3]); } #endif 

Dann können Sie den folgenden Code ausführen:

 // Misc. bool HW_MMX; bool HW_x64; bool HW_ABM; // Advanced Bit Manipulation bool HW_RDRAND; bool HW_BMI1; bool HW_BMI2; bool HW_ADX; bool HW_PREFETCHWT1; // SIMD: 128-bit bool HW_SSE; bool HW_SSE2; bool HW_SSE3; bool HW_SSSE3; bool HW_SSE41; bool HW_SSE42; bool HW_SSE4a; bool HW_AES; bool HW_SHA; // SIMD: 256-bit bool HW_AVX; bool HW_XOP; bool HW_FMA3; bool HW_FMA4; bool HW_AVX2; // SIMD: 512-bit bool HW_AVX512F; // AVX512 Foundation bool HW_AVX512CD; // AVX512 Conflict Detection bool HW_AVX512PF; // AVX512 Prefetch bool HW_AVX512ER; // AVX512 Exponential + Reciprocal bool HW_AVX512VL; // AVX512 Vector Length Extensions bool HW_AVX512BW; // AVX512 Byte + Word bool HW_AVX512DQ; // AVX512 Doubleword + Quadword bool HW_AVX512IFMA; // AVX512 Integer 52-bit Fused Multiply-Add bool HW_AVX512VBMI; // AVX512 Vector Byte Manipulation Instructions int info[4]; cpuid(info, 0); int nIds = info[0]; cpuid(info, 0x80000000); unsigned nExIds = info[0]; // Detect Features if (nIds >= 0x00000001){ cpuid(info,0x00000001); HW_MMX = (info[3] & ((int)1 < < 23)) != 0; HW_SSE = (info[3] & ((int)1 << 25)) != 0; HW_SSE2 = (info[3] & ((int)1 << 26)) != 0; HW_SSE3 = (info[2] & ((int)1 << 0)) != 0; HW_SSSE3 = (info[2] & ((int)1 << 9)) != 0; HW_SSE41 = (info[2] & ((int)1 << 19)) != 0; HW_SSE42 = (info[2] & ((int)1 << 20)) != 0; HW_AES = (info[2] & ((int)1 << 25)) != 0; HW_AVX = (info[2] & ((int)1 << 28)) != 0; HW_FMA3 = (info[2] & ((int)1 << 12)) != 0; HW_RDRAND = (info[2] & ((int)1 << 30)) != 0; } if (nIds >= 0x00000007){ cpuid(info,0x00000007); HW_AVX2 = (info[1] & ((int)1 < < 5)) != 0; HW_BMI1 = (info[1] & ((int)1 << 3)) != 0; HW_BMI2 = (info[1] & ((int)1 << 8)) != 0; HW_ADX = (info[1] & ((int)1 << 19)) != 0; HW_SHA = (info[1] & ((int)1 << 29)) != 0; HW_PREFETCHWT1 = (info[2] & ((int)1 << 0)) != 0; HW_AVX512F = (info[1] & ((int)1 << 16)) != 0; HW_AVX512CD = (info[1] & ((int)1 << 28)) != 0; HW_AVX512PF = (info[1] & ((int)1 << 26)) != 0; HW_AVX512ER = (info[1] & ((int)1 << 27)) != 0; HW_AVX512VL = (info[1] & ((int)1 << 31)) != 0; HW_AVX512BW = (info[1] & ((int)1 << 30)) != 0; HW_AVX512DQ = (info[1] & ((int)1 << 17)) != 0; HW_AVX512IFMA = (info[1] & ((int)1 << 21)) != 0; HW_AVX512VBMI = (info[2] & ((int)1 << 1)) != 0; } if (nExIds >= 0x80000001){ cpuid(info,0x80000001); HW_x64 = (info[3] & ((int)1 < < 29)) != 0; HW_ABM = (info[2] & ((int)1 << 5)) != 0; HW_SSE4a = (info[2] & ((int)1 << 6)) != 0; HW_FMA4 = (info[2] & ((int)1 << 16)) != 0; HW_XOP = (info[2] & ((int)1 << 11)) != 0; } 

Beachten Sie, dass dies nur erkennt, ob die CPU die statementen unterstützt. Um sie tatsächlich ausführen zu können, benötigen Sie auch Betriebssystemunterstützung.

Insbesondere ist Betriebssystemunterstützung erforderlich für:

  • x64 statementen. (Sie benötigen ein 64-Bit-Betriebssystem.)
  • statementen, die die (AVX) 256-Bit- ymm Register verwenden. Siehe Andy Lutomirskis Antwort, wie man dies erkennt .
  • statementen, die das (AVX512) 512-Bit- zmm und zmm . Die Erkennung der Betriebssystemunterstützung für AVX512 ist dieselbe wie für AVX, jedoch unter Verwendung des Flags 0xe6 anstelle von 0x6 .

Mysticials Antwort ist ein bisschen gefährlich – es erklärt, wie man die CPU-Unterstützung erkennt, aber nicht die Betriebssystem-Unterstützung. Sie müssen _xgetbv verwenden, um zu überprüfen, ob das Betriebssystem den erforderlichen erweiterten CPU-Status aktiviert hat. Siehe hier für eine andere Quelle. Selbst gcc hat den gleichen Fehler gemacht. Das Fleisch des Codes ist:

 bool avxSupported = false; int cpuInfo[4]; __cpuid(cpuInfo, 1); bool osUsesXSAVE_XRSTORE = cpuInfo[2] & (1 < < 27) || false; bool cpuAVXSuport = cpuInfo[2] & (1 << 28) || false; if (osUsesXSAVE_XRSTORE && cpuAVXSuport) { unsigned long long xcrFeatureMask = _xgetbv(_XCR_XFEATURE_ENABLED_MASK); avxSupported = (xcrFeatureMask & 0x6) == 0x6; } 

Nach einigem Googeln habe ich auch die Lösungen von Intel gefunden:

Link: https://software.intel.com/en-us/articles/how-to-tect-new-instruction-support-in-the-4th-generation-intel-core-processor-family

  void cpuid(uint32_t eax, uint32_t ecx, uint32_t* abcd) { #if defined(_MSC_VER) __cpuidex((int*)abcd, eax, ecx); #else uint32_t ebx, edx; # if defined( __i386__ ) && defined ( __PIC__ ) /* in case of PIC under 32-bit EBX cannot be clobbered */ __asm__("movl %%ebx, %%edi \n\t cpuid \n\t xchgl %%ebx, %%edi" : "=D" (ebx), # else __asm__("cpuid" : "+b" (ebx), # endif "+a" (eax), "+c" (ecx), "=d" (edx)); abcd[0] = eax; abcd[1] = ebx; abcd[2] = ecx; abcd[3] = edx; #endif } int check_xcr0_ymm() { uint32_t xcr0; #if defined(_MSC_VER) xcr0 = (uint32_t)_xgetbv(0); /* min VS2010 SP1 compiler is required */ #else __asm__("xgetbv" : "=a" (xcr0) : "c" (0) : "%edx"); #endif return ((xcr0 & 6) == 6); /* checking if xmm and ymm state are enabled in XCR0 */ } 

Beachten Sie auch, dass GCC einige spezielle Eigenschaften enthält, die Sie verwenden können (siehe: https://gcc.gnu.org/onlinedocs/gcc-4.9.2/gcc/X86-Built-in-Functions.html ):

  if (__builtin_cpu_supports("avx2")) // ... 

Wenn Sie dies mit den obigen Informationen zusammenfügen, wird alles gut gehen.

Auf einem Mac OS funktioniert das:

 sysctl -a | grep machdep.cpu.features 

In meiner Maschine gibt es folgendes aus:

machdep.cpu.features: FPU VME DE PSE TSC MSR PAE MCE CX8 APIC SEP MTRR PGE MCA CMOV PAT PSE36 CLFSH DS ACPI MMX FXSR SSE SSE2 SS HTT TM PBE SSE3 PCLMULQDQ DTES64 MON DSCPL VMX EST TM2 SSSE3 FMA CX16 TPR PDCM SSE4.1 SSE4.2 x2APIC MOVBE POPCNT AES PCID XSAVE OSXSAVE SEGLIM64 TSCTMR AVX1.0 RDRAND F16C

Wie Sie anhand der fett gedruckten statementen sehen können, werden SSE3 und einige andere SIMD-statementen unterstützt.

Um Abhiroops Antwort hinzuzufügen: Unter Linux können Sie diesen Shell-Befehl ausführen, um die von Ihrer CPU unterstützten functionen zu ermitteln

cat /proc/cpuinfo | grep flags | uniq

Auf meiner Maschine druckt das

flags: fpu vme de pse tsc msr pae mcx cx8 apic sep mtrr pge mca cmov pat pse36 klflush mmx fxsr sse sse2 ht syscall nx pdpe1gb rdtscp lm konstant_tsc rep_good nopl xtopology nonstop_tsc aperfmperf eifrigfpu pni pclmulqdq ssse3 fmacx16 pcid sse4_1 sse4_2 x2apic move popcnt tsc_deadline_timer aes xsave avx f16c rdrand hypervisor lahf_lm abm 3dnowprefetch invpcid_single repoline kaiser fsgsbase bmi1 hle avx2 smep bmi2 ers invpcide rtm rdseed adx xsaveopt