cpu_detect.cpp 5.7 KB

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