cpu_detect.cpp 5.7 KB

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