cpu_detect.cpp 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  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 "common/common_types.h"
  6. #include "common/x64/cpu_detect.h"
  7. #ifdef _MSC_VER
  8. #include <intrin.h>
  9. #else
  10. #if defined(__DragonFly__) || defined(__FreeBSD__)
  11. // clang-format off
  12. #include <sys/types.h>
  13. #include <machine/cpufunc.h>
  14. // clang-format on
  15. #endif
  16. static inline void __cpuidex(int info[4], int function_id, int subfunction_id) {
  17. #if defined(__DragonFly__) || defined(__FreeBSD__)
  18. // Despite the name, this is just do_cpuid() with ECX as second input.
  19. cpuid_count((u_int)function_id, (u_int)subfunction_id, (u_int*)info);
  20. #else
  21. info[0] = function_id; // eax
  22. info[2] = subfunction_id; // ecx
  23. __asm__("cpuid"
  24. : "=a"(info[0]), "=b"(info[1]), "=c"(info[2]), "=d"(info[3])
  25. : "a"(function_id), "c"(subfunction_id));
  26. #endif
  27. }
  28. static inline void __cpuid(int info[4], int function_id) {
  29. return __cpuidex(info, function_id, 0);
  30. }
  31. #define _XCR_XFEATURE_ENABLED_MASK 0
  32. static inline u64 _xgetbv(u32 index) {
  33. u32 eax, edx;
  34. __asm__ __volatile__("xgetbv" : "=a"(eax), "=d"(edx) : "c"(index));
  35. return ((u64)edx << 32) | eax;
  36. }
  37. #endif // _MSC_VER
  38. namespace Common {
  39. // Detects the various CPU features
  40. static CPUCaps Detect() {
  41. CPUCaps caps = {};
  42. // Assumes the CPU supports the CPUID instruction. Those that don't would likely not support
  43. // yuzu at all anyway
  44. int cpu_id[4];
  45. memset(caps.brand_string, 0, sizeof(caps.brand_string));
  46. // Detect CPU's CPUID capabilities and grab CPU string
  47. __cpuid(cpu_id, 0x00000000);
  48. u32 max_std_fn = cpu_id[0]; // EAX
  49. std::memcpy(&caps.brand_string[0], &cpu_id[1], sizeof(int));
  50. std::memcpy(&caps.brand_string[4], &cpu_id[3], sizeof(int));
  51. std::memcpy(&caps.brand_string[8], &cpu_id[2], sizeof(int));
  52. if (cpu_id[1] == 0x756e6547 && cpu_id[2] == 0x6c65746e && cpu_id[3] == 0x49656e69)
  53. caps.manufacturer = Manufacturer::Intel;
  54. else if (cpu_id[1] == 0x68747541 && cpu_id[2] == 0x444d4163 && cpu_id[3] == 0x69746e65)
  55. caps.manufacturer = Manufacturer::AMD;
  56. else if (cpu_id[1] == 0x6f677948 && cpu_id[2] == 0x656e6975 && cpu_id[3] == 0x6e65476e)
  57. caps.manufacturer = Manufacturer::Hygon;
  58. else
  59. caps.manufacturer = Manufacturer::Unknown;
  60. u32 family = {};
  61. u32 model = {};
  62. __cpuid(cpu_id, 0x80000000);
  63. u32 max_ex_fn = cpu_id[0];
  64. // Set reasonable default brand string even if brand string not available
  65. strcpy(caps.cpu_string, caps.brand_string);
  66. // Detect family and other miscellaneous features
  67. if (max_std_fn >= 1) {
  68. __cpuid(cpu_id, 0x00000001);
  69. family = (cpu_id[0] >> 8) & 0xf;
  70. model = (cpu_id[0] >> 4) & 0xf;
  71. if (family == 0xf) {
  72. family += (cpu_id[0] >> 20) & 0xff;
  73. }
  74. if (family >= 6) {
  75. model += ((cpu_id[0] >> 16) & 0xf) << 4;
  76. }
  77. if ((cpu_id[3] >> 25) & 1)
  78. caps.sse = true;
  79. if ((cpu_id[3] >> 26) & 1)
  80. caps.sse2 = true;
  81. if ((cpu_id[2]) & 1)
  82. caps.sse3 = true;
  83. if ((cpu_id[2] >> 9) & 1)
  84. caps.ssse3 = true;
  85. if ((cpu_id[2] >> 19) & 1)
  86. caps.sse4_1 = true;
  87. if ((cpu_id[2] >> 20) & 1)
  88. caps.sse4_2 = true;
  89. if ((cpu_id[2] >> 25) & 1)
  90. caps.aes = true;
  91. // AVX support requires 3 separate checks:
  92. // - Is the AVX bit set in CPUID?
  93. // - Is the XSAVE bit set in CPUID?
  94. // - XGETBV result has the XCR bit set.
  95. if (((cpu_id[2] >> 28) & 1) && ((cpu_id[2] >> 27) & 1)) {
  96. if ((_xgetbv(_XCR_XFEATURE_ENABLED_MASK) & 0x6) == 0x6) {
  97. caps.avx = true;
  98. if ((cpu_id[2] >> 12) & 1)
  99. caps.fma = true;
  100. }
  101. }
  102. if (max_std_fn >= 7) {
  103. __cpuidex(cpu_id, 0x00000007, 0x00000000);
  104. // Can't enable AVX2 unless the XSAVE/XGETBV checks above passed
  105. if ((cpu_id[1] >> 5) & 1)
  106. caps.avx2 = caps.avx;
  107. if ((cpu_id[1] >> 3) & 1)
  108. caps.bmi1 = true;
  109. if ((cpu_id[1] >> 8) & 1)
  110. caps.bmi2 = true;
  111. // Checks for AVX512F, AVX512CD, AVX512VL, AVX512DQ, AVX512BW (Intel Skylake-X/SP)
  112. if ((cpu_id[1] >> 16) & 1 && (cpu_id[1] >> 28) & 1 && (cpu_id[1] >> 31) & 1 &&
  113. (cpu_id[1] >> 17) & 1 && (cpu_id[1] >> 30) & 1) {
  114. caps.avx512 = caps.avx2;
  115. }
  116. }
  117. }
  118. if (max_ex_fn >= 0x80000004) {
  119. // Extract CPU model string
  120. __cpuid(cpu_id, 0x80000002);
  121. std::memcpy(caps.cpu_string, cpu_id, sizeof(cpu_id));
  122. __cpuid(cpu_id, 0x80000003);
  123. std::memcpy(caps.cpu_string + 16, cpu_id, sizeof(cpu_id));
  124. __cpuid(cpu_id, 0x80000004);
  125. std::memcpy(caps.cpu_string + 32, cpu_id, sizeof(cpu_id));
  126. }
  127. if (max_ex_fn >= 0x80000001) {
  128. // Check for more features
  129. __cpuid(cpu_id, 0x80000001);
  130. if ((cpu_id[2] >> 16) & 1)
  131. caps.fma4 = true;
  132. }
  133. if (max_ex_fn >= 0x80000007) {
  134. __cpuid(cpu_id, 0x80000007);
  135. if (cpu_id[3] & (1 << 8)) {
  136. caps.invariant_tsc = true;
  137. }
  138. }
  139. if (max_std_fn >= 0x16) {
  140. __cpuid(cpu_id, 0x16);
  141. caps.base_frequency = cpu_id[0];
  142. caps.max_frequency = cpu_id[1];
  143. caps.bus_frequency = cpu_id[2];
  144. }
  145. return caps;
  146. }
  147. const CPUCaps& GetCPUCaps() {
  148. static CPUCaps caps = Detect();
  149. return caps;
  150. }
  151. } // namespace Common