mptCPU.cpp 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258
  1. /*
  2. * mptCPU.cpp
  3. * ----------
  4. * Purpose: CPU feature detection.
  5. * Notes : (currently none)
  6. * Authors: OpenMPT Devs
  7. * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
  8. */
  9. #include "stdafx.h"
  10. #include "mptCPU.h"
  11. #include "../common/mptStringBuffer.h"
  12. #if defined(MPT_ENABLE_ARCH_INTRINSICS)
  13. #if MPT_COMPILER_MSVC && (defined(MPT_ENABLE_ARCH_X86) || defined(MPT_ENABLE_ARCH_AMD64))
  14. #include <intrin.h>
  15. #endif // MPT_COMPILER_MSVC && (MPT_ENABLE_ARCH_X86 || MPT_ENABLE_ARCH_AMD64)
  16. #endif // MPT_ENABLE_ARCH_INTRINSICS
  17. OPENMPT_NAMESPACE_BEGIN
  18. namespace CPU
  19. {
  20. #if defined(MPT_ENABLE_ARCH_INTRINSICS)
  21. uint32 EnabledFeatures = 0;
  22. #if MPT_COMPILER_MSVC && (defined(MPT_ENABLE_ARCH_X86) || defined(MPT_ENABLE_ARCH_AMD64))
  23. typedef char cpuid_result_string[12];
  24. struct cpuid_result {
  25. uint32 a;
  26. uint32 b;
  27. uint32 c;
  28. uint32 d;
  29. std::string as_string() const
  30. {
  31. cpuid_result_string result;
  32. result[0+0] = (b >> 0) & 0xff;
  33. result[0+1] = (b >> 8) & 0xff;
  34. result[0+2] = (b >>16) & 0xff;
  35. result[0+3] = (b >>24) & 0xff;
  36. result[4+0] = (d >> 0) & 0xff;
  37. result[4+1] = (d >> 8) & 0xff;
  38. result[4+2] = (d >>16) & 0xff;
  39. result[4+3] = (d >>24) & 0xff;
  40. result[8+0] = (c >> 0) & 0xff;
  41. result[8+1] = (c >> 8) & 0xff;
  42. result[8+2] = (c >>16) & 0xff;
  43. result[8+3] = (c >>24) & 0xff;
  44. return std::string(result, result + 12);
  45. }
  46. std::string as_string4() const
  47. {
  48. std::string result;
  49. result.push_back(static_cast<uint8>((a >> 0) & 0xff));
  50. result.push_back(static_cast<uint8>((a >> 8) & 0xff));
  51. result.push_back(static_cast<uint8>((a >> 16) & 0xff));
  52. result.push_back(static_cast<uint8>((a >> 24) & 0xff));
  53. result.push_back(static_cast<uint8>((b >> 0) & 0xff));
  54. result.push_back(static_cast<uint8>((b >> 8) & 0xff));
  55. result.push_back(static_cast<uint8>((b >> 16) & 0xff));
  56. result.push_back(static_cast<uint8>((b >> 24) & 0xff));
  57. result.push_back(static_cast<uint8>((c >> 0) & 0xff));
  58. result.push_back(static_cast<uint8>((c >> 8) & 0xff));
  59. result.push_back(static_cast<uint8>((c >> 16) & 0xff));
  60. result.push_back(static_cast<uint8>((c >> 24) & 0xff));
  61. result.push_back(static_cast<uint8>((d >> 0) & 0xff));
  62. result.push_back(static_cast<uint8>((d >> 8) & 0xff));
  63. result.push_back(static_cast<uint8>((d >> 16) & 0xff));
  64. result.push_back(static_cast<uint8>((d >> 24) & 0xff));
  65. return result;
  66. }
  67. };
  68. static cpuid_result cpuid(uint32 function)
  69. {
  70. cpuid_result result;
  71. int CPUInfo[4];
  72. __cpuid(CPUInfo, function);
  73. result.a = CPUInfo[0];
  74. result.b = CPUInfo[1];
  75. result.c = CPUInfo[2];
  76. result.d = CPUInfo[3];
  77. return result;
  78. }
  79. static cpuid_result cpuidex(uint32 function_a, uint32 function_c)
  80. {
  81. cpuid_result result;
  82. int CPUInfo[4];
  83. __cpuidex(CPUInfo, function_a, function_c);
  84. result.a = CPUInfo[0];
  85. result.b = CPUInfo[1];
  86. result.c = CPUInfo[2];
  87. result.d = CPUInfo[3];
  88. return result;
  89. }
  90. Info::Info()
  91. {
  92. cpuid_result VendorString = cpuid(0x00000000u);
  93. mpt::String::WriteAutoBuf(VendorID) = VendorString.as_string();
  94. if(VendorString.a >= 0x00000001u)
  95. {
  96. cpuid_result StandardFeatureFlags = cpuid(0x00000001u);
  97. CPUID = StandardFeatureFlags.a;
  98. uint32 BaseStepping = (StandardFeatureFlags.a >> 0) & 0x0f;
  99. uint32 BaseModel = (StandardFeatureFlags.a >> 4) & 0x0f;
  100. uint32 BaseFamily = (StandardFeatureFlags.a >> 8) & 0x0f;
  101. uint32 ExtModel = (StandardFeatureFlags.a >> 16) & 0x0f;
  102. uint32 ExtFamily = (StandardFeatureFlags.a >> 20) & 0xff;
  103. if(BaseFamily == 0xf)
  104. {
  105. Family = static_cast<uint16>(ExtFamily + BaseFamily);
  106. } else
  107. {
  108. Family = static_cast<uint16>(BaseFamily);
  109. }
  110. if((BaseFamily == 0x6) || (BaseFamily == 0xf))
  111. {
  112. Model = static_cast<uint8>((ExtModel << 4) | (BaseModel << 0));
  113. } else
  114. {
  115. Model = static_cast<uint8>(BaseModel);
  116. }
  117. Stepping = static_cast<uint8>(BaseStepping);
  118. if(StandardFeatureFlags.d & (1<<23)) AvailableFeatures |= feature::mmx;
  119. if(StandardFeatureFlags.d & (1<<25)) AvailableFeatures |= feature::sse;
  120. if(StandardFeatureFlags.d & (1<<26)) AvailableFeatures |= feature::sse2;
  121. if(StandardFeatureFlags.c & (1<< 0)) AvailableFeatures |= feature::sse3;
  122. if(StandardFeatureFlags.c & (1<< 9)) AvailableFeatures |= feature::ssse3;
  123. if(StandardFeatureFlags.c & (1<<19)) AvailableFeatures |= feature::sse4_1;
  124. if(StandardFeatureFlags.c & (1<<20)) AvailableFeatures |= feature::sse4_2;
  125. if(StandardFeatureFlags.c & (1<<28)) AvailableFeatures |= feature::avx;
  126. }
  127. if(VendorString.a >= 0x00000007u)
  128. {
  129. cpuid_result ExtendedFeatures = cpuidex(0x00000007u, 0x00000000u);
  130. if(ExtendedFeatures.b & (1<< 5)) AvailableFeatures |= feature::avx2;
  131. }
  132. cpuid_result ExtendedVendorString = cpuid(0x80000000u);
  133. if(ExtendedVendorString.a >= 0x80000001u)
  134. {
  135. cpuid_result ExtendedFeatureFlags = cpuid(0x80000001u);
  136. if(ExtendedFeatureFlags.d & (1<<29)) AvailableFeatures |= feature::lm;
  137. }
  138. if(ExtendedVendorString.a >= 0x80000004u)
  139. {
  140. mpt::String::WriteAutoBuf(BrandID) = cpuid(0x80000002u).as_string4() + cpuid(0x80000003u).as_string4() + cpuid(0x80000004u).as_string4();
  141. }
  142. }
  143. #elif MPT_COMPILER_MSVC && (defined(MPT_ENABLE_ARCH_X86) || defined(MPT_ENABLE_ARCH_AMD64))
  144. Info::Info()
  145. {
  146. if(IsProcessorFeaturePresent(PF_MMX_INSTRUCTIONS_AVAILABLE) != 0) AvailableFeatures |= feature::mmx;
  147. if(IsProcessorFeaturePresent(PF_XMMI_INSTRUCTIONS_AVAILABLE) != 0) AvailableFeatures |= feature::sse;
  148. if(IsProcessorFeaturePresent(PF_XMMI64_INSTRUCTIONS_AVAILABLE) != 0) AvailableFeatures |= feature::sse2;
  149. if(IsProcessorFeaturePresent(PF_SSE3_INSTRUCTIONS_AVAILABLE) != 0) AvailableFeatures |= feature::sse3;
  150. }
  151. #else // !(MPT_COMPILER_MSVC && (MPT_ENABLE_ARCH_X86 || MPT_ENABLE_ARCH_AMD64))
  152. Info::Info()
  153. {
  154. return;
  155. }
  156. #endif // MPT_COMPILER_MSVC && (MPT_ENABLE_ARCH_X86 || MPT_ENABLE_ARCH_AMD64)
  157. const Info & Info::Get()
  158. {
  159. static Info info;
  160. return info;
  161. }
  162. struct InfoInitializer
  163. {
  164. InfoInitializer()
  165. {
  166. Info::Get();
  167. }
  168. };
  169. static InfoInitializer g_InfoInitializer;
  170. void EnableAvailableFeatures()
  171. {
  172. EnabledFeatures = Info::Get().AvailableFeatures;
  173. }
  174. #endif // MPT_ENABLE_ARCH_INTRINSICS
  175. uint32 GetMinimumFeatures()
  176. {
  177. uint32 flags = 0;
  178. #ifdef MPT_ENABLE_ARCH_INTRINSICS
  179. #if MPT_COMPILER_MSVC
  180. #if defined(_M_X64)
  181. flags |= feature::lm | feature::sse | feature::sse2;
  182. #elif defined(_M_IX86)
  183. #if defined(_M_IX86_FP)
  184. #if (_M_IX86_FP >= 2)
  185. flags |= feature::sse | feature::sse2;
  186. #elif (_M_IX86_FP == 1)
  187. flags |= feature::sse;
  188. #endif
  189. #endif
  190. #endif
  191. #if defined(__AVX__)
  192. flags |= feature::avx;
  193. #endif
  194. #if defined(__AVX2__)
  195. flags |= feature::avx2;
  196. #endif
  197. #endif
  198. #endif // MPT_ENABLE_ARCH_INTRINSICS
  199. return flags;
  200. }
  201. } // namespace CPU
  202. OPENMPT_NAMESPACE_END