cpu_detect.cpp 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. // Copyright 2013 Dolphin Emulator Project / 2015 Citra Emulator Project
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #include <cstring>
  5. #include <string>
  6. #include <thread>
  7. #include "common/common_types.h"
  8. #include "cpu_detect.h"
  9. namespace Common {
  10. #ifndef _MSC_VER
  11. #ifdef __FreeBSD__
  12. #include <sys/types.h>
  13. #include <machine/cpufunc.h>
  14. #endif
  15. static inline void __cpuidex(int info[4], int function_id, int subfunction_id) {
  16. #ifdef __FreeBSD__
  17. // Despite the name, this is just do_cpuid() with ECX as second input.
  18. cpuid_count((u_int)function_id, (u_int)subfunction_id, (u_int*)info);
  19. #else
  20. info[0] = function_id; // eax
  21. info[2] = subfunction_id; // ecx
  22. __asm__(
  23. "cpuid"
  24. : "=a" (info[0]),
  25. "=b" (info[1]),
  26. "=c" (info[2]),
  27. "=d" (info[3])
  28. : "a" (function_id),
  29. "c" (subfunction_id)
  30. );
  31. #endif
  32. }
  33. static inline void __cpuid(int info[4], int function_id) {
  34. return __cpuidex(info, function_id, 0);
  35. }
  36. #define _XCR_XFEATURE_ENABLED_MASK 0
  37. static u64 _xgetbv(u32 index) {
  38. u32 eax, edx;
  39. __asm__ __volatile__("xgetbv" : "=a"(eax), "=d"(edx) : "c"(index));
  40. return ((u64)edx << 32) | eax;
  41. }
  42. #endif // ifndef _MSC_VER
  43. // Detects the various CPU features
  44. static CPUCaps Detect() {
  45. CPUCaps caps = {};
  46. caps.num_cores = std::thread::hardware_concurrency();
  47. // Assumes the CPU supports the CPUID instruction. Those that don't would likely not support
  48. // Citra at all anyway
  49. int cpu_id[4];
  50. memset(caps.brand_string, 0, sizeof(caps.brand_string));
  51. // Detect CPU's CPUID capabilities and grab CPU string
  52. __cpuid(cpu_id, 0x00000000);
  53. u32 max_std_fn = cpu_id[0]; // EAX
  54. std::memcpy(&caps.brand_string[0], &cpu_id[1], sizeof(int));
  55. std::memcpy(&caps.brand_string[4], &cpu_id[3], sizeof(int));
  56. std::memcpy(&caps.brand_string[8], &cpu_id[2], sizeof(int));
  57. __cpuid(cpu_id, 0x80000000);
  58. u32 max_ex_fn = cpu_id[0];
  59. if (!strcmp(caps.brand_string, "GenuineIntel"))
  60. caps.vendor = CPUVendor::INTEL;
  61. else if (!strcmp(caps.brand_string, "AuthenticAMD"))
  62. caps.vendor = CPUVendor::AMD;
  63. else
  64. caps.vendor = CPUVendor::OTHER;
  65. // Set reasonable default brand string even if brand string not available
  66. strcpy(caps.cpu_string, caps.brand_string);
  67. // Detect family and other miscellaneous features
  68. if (max_std_fn >= 1) {
  69. __cpuid(cpu_id, 0x00000001);
  70. if ((cpu_id[3] >> 25) & 1) caps.sse = true;
  71. if ((cpu_id[3] >> 26) & 1) caps.sse2 = true;
  72. if ((cpu_id[2]) & 1) caps.sse3 = true;
  73. if ((cpu_id[2] >> 9) & 1) caps.ssse3 = true;
  74. if ((cpu_id[2] >> 19) & 1) caps.sse4_1 = true;
  75. if ((cpu_id[2] >> 20) & 1) caps.sse4_2 = true;
  76. if ((cpu_id[2] >> 22) & 1) caps.movbe = true;
  77. if ((cpu_id[2] >> 25) & 1) caps.aes = true;
  78. if ((cpu_id[3] >> 24) & 1) {
  79. caps.fxsave_fxrstor = true;
  80. }
  81. // AVX support requires 3 separate checks:
  82. // - Is the AVX bit set in CPUID?
  83. // - Is the XSAVE bit set in CPUID?
  84. // - XGETBV result has the XCR bit set.
  85. if (((cpu_id[2] >> 28) & 1) && ((cpu_id[2] >> 27) & 1)) {
  86. if ((_xgetbv(_XCR_XFEATURE_ENABLED_MASK) & 0x6) == 0x6) {
  87. caps.avx = true;
  88. if ((cpu_id[2] >> 12) & 1)
  89. caps.fma = true;
  90. }
  91. }
  92. if (max_std_fn >= 7) {
  93. __cpuidex(cpu_id, 0x00000007, 0x00000000);
  94. // Can't enable AVX2 unless the XSAVE/XGETBV checks above passed
  95. if ((cpu_id[1] >> 5) & 1)
  96. caps.avx2 = caps.avx;
  97. if ((cpu_id[1] >> 3) & 1)
  98. caps.bmi1 = true;
  99. if ((cpu_id[1] >> 8) & 1)
  100. caps.bmi2 = true;
  101. }
  102. }
  103. caps.flush_to_zero = caps.sse;
  104. if (max_ex_fn >= 0x80000004) {
  105. // Extract CPU model string
  106. __cpuid(cpu_id, 0x80000002);
  107. std::memcpy(caps.cpu_string, cpu_id, sizeof(cpu_id));
  108. __cpuid(cpu_id, 0x80000003);
  109. std::memcpy(caps.cpu_string + 16, cpu_id, sizeof(cpu_id));
  110. __cpuid(cpu_id, 0x80000004);
  111. std::memcpy(caps.cpu_string + 32, cpu_id, sizeof(cpu_id));
  112. }
  113. if (max_ex_fn >= 0x80000001) {
  114. // Check for more features
  115. __cpuid(cpu_id, 0x80000001);
  116. if (cpu_id[2] & 1) caps.lahf_sahf_64 = true;
  117. if ((cpu_id[2] >> 5) & 1) caps.lzcnt = true;
  118. if ((cpu_id[2] >> 16) & 1) caps.fma4 = true;
  119. if ((cpu_id[3] >> 29) & 1) caps.long_mode = true;
  120. }
  121. return caps;
  122. }
  123. const CPUCaps& GetCPUCaps() {
  124. static CPUCaps caps = Detect();
  125. return caps;
  126. }
  127. std::string GetCPUCapsString() {
  128. auto caps = GetCPUCaps();
  129. std::string sum(caps.cpu_string);
  130. sum += " (";
  131. sum += caps.brand_string;
  132. sum += ")";
  133. if (caps.sse) sum += ", SSE";
  134. if (caps.sse2) {
  135. sum += ", SSE2";
  136. if (!caps.flush_to_zero) sum += " (without DAZ)";
  137. }
  138. if (caps.sse3) sum += ", SSE3";
  139. if (caps.ssse3) sum += ", SSSE3";
  140. if (caps.sse4_1) sum += ", SSE4.1";
  141. if (caps.sse4_2) sum += ", SSE4.2";
  142. if (caps.avx) sum += ", AVX";
  143. if (caps.avx2) sum += ", AVX2";
  144. if (caps.bmi1) sum += ", BMI1";
  145. if (caps.bmi2) sum += ", BMI2";
  146. if (caps.fma) sum += ", FMA";
  147. if (caps.aes) sum += ", AES";
  148. if (caps.movbe) sum += ", MOVBE";
  149. if (caps.long_mode) sum += ", 64-bit support";
  150. return sum;
  151. }
  152. } // namespace Common