🛠️🐜 Antkeeper superbuild with dependencies included https://antkeeper.com
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

141 lines
4.3 KiB

  1. #include "config.h"
  2. #include "cpu_caps.h"
  3. #if defined(_WIN32) && (defined(_M_ARM) || defined(_M_ARM64))
  4. #define WIN32_LEAN_AND_MEAN
  5. #include <windows.h>
  6. #ifndef PF_ARM_NEON_INSTRUCTIONS_AVAILABLE
  7. #define PF_ARM_NEON_INSTRUCTIONS_AVAILABLE 19
  8. #endif
  9. #endif
  10. #if defined(HAVE_CPUID_H)
  11. #include <cpuid.h>
  12. #elif defined(HAVE_INTRIN_H)
  13. #include <intrin.h>
  14. #endif
  15. #include <array>
  16. #include <cctype>
  17. #include <string>
  18. int CPUCapFlags{0};
  19. namespace {
  20. #if defined(HAVE_GCC_GET_CPUID) \
  21. && (defined(__i386__) || defined(__x86_64__) || defined(_M_IX86) || defined(_M_X64))
  22. using reg_type = unsigned int;
  23. inline std::array<reg_type,4> get_cpuid(unsigned int f)
  24. {
  25. std::array<reg_type,4> ret{};
  26. __get_cpuid(f, &ret[0], &ret[1], &ret[2], &ret[3]);
  27. return ret;
  28. }
  29. #define CAN_GET_CPUID
  30. #elif defined(HAVE_CPUID_INTRINSIC) \
  31. && (defined(__i386__) || defined(__x86_64__) || defined(_M_IX86) || defined(_M_X64))
  32. using reg_type = int;
  33. inline std::array<reg_type,4> get_cpuid(unsigned int f)
  34. {
  35. std::array<reg_type,4> ret{};
  36. (__cpuid)(ret.data(), f);
  37. return ret;
  38. }
  39. #define CAN_GET_CPUID
  40. #endif
  41. } // namespace
  42. al::optional<CPUInfo> GetCPUInfo()
  43. {
  44. CPUInfo ret;
  45. #ifdef CAN_GET_CPUID
  46. auto cpuregs = get_cpuid(0);
  47. if(cpuregs[0] == 0)
  48. return al::nullopt;
  49. const reg_type maxfunc{cpuregs[0]};
  50. cpuregs = get_cpuid(0x80000000);
  51. const reg_type maxextfunc{cpuregs[0]};
  52. ret.mVendor.append(reinterpret_cast<char*>(&cpuregs[1]), 4);
  53. ret.mVendor.append(reinterpret_cast<char*>(&cpuregs[3]), 4);
  54. ret.mVendor.append(reinterpret_cast<char*>(&cpuregs[2]), 4);
  55. auto iter_end = std::remove(ret.mVendor.begin(), ret.mVendor.end(), '\0');
  56. iter_end = std::unique(ret.mVendor.begin(), iter_end,
  57. [](auto&& c0, auto&& c1) { return std::isspace(c0) && std::isspace(c1); });
  58. ret.mVendor.erase(iter_end, ret.mVendor.end());
  59. if(!ret.mVendor.empty() && std::isspace(ret.mVendor.back()))
  60. ret.mVendor.pop_back();
  61. if(!ret.mVendor.empty() && std::isspace(ret.mVendor.front()))
  62. ret.mVendor.erase(ret.mVendor.begin());
  63. if(maxextfunc >= 0x80000004)
  64. {
  65. cpuregs = get_cpuid(0x80000002);
  66. ret.mName.append(reinterpret_cast<char*>(cpuregs.data()), 16);
  67. cpuregs = get_cpuid(0x80000003);
  68. ret.mName.append(reinterpret_cast<char*>(cpuregs.data()), 16);
  69. cpuregs = get_cpuid(0x80000004);
  70. ret.mName.append(reinterpret_cast<char*>(cpuregs.data()), 16);
  71. iter_end = std::remove(ret.mName.begin(), ret.mName.end(), '\0');
  72. iter_end = std::unique(ret.mName.begin(), iter_end,
  73. [](auto&& c0, auto&& c1) { return std::isspace(c0) && std::isspace(c1); });
  74. ret.mName.erase(iter_end, ret.mName.end());
  75. if(!ret.mName.empty() && std::isspace(ret.mName.back()))
  76. ret.mName.pop_back();
  77. if(!ret.mName.empty() && std::isspace(ret.mName.front()))
  78. ret.mName.erase(ret.mName.begin());
  79. }
  80. if(maxfunc >= 1)
  81. {
  82. cpuregs = get_cpuid(1);
  83. if((cpuregs[3]&(1<<25)))
  84. ret.mCaps |= CPU_CAP_SSE;
  85. if((ret.mCaps&CPU_CAP_SSE) && (cpuregs[3]&(1<<26)))
  86. ret.mCaps |= CPU_CAP_SSE2;
  87. if((ret.mCaps&CPU_CAP_SSE2) && (cpuregs[2]&(1<<0)))
  88. ret.mCaps |= CPU_CAP_SSE3;
  89. if((ret.mCaps&CPU_CAP_SSE3) && (cpuregs[2]&(1<<19)))
  90. ret.mCaps |= CPU_CAP_SSE4_1;
  91. }
  92. #else
  93. /* Assume support for whatever's supported if we can't check for it */
  94. #if defined(HAVE_SSE4_1)
  95. #warning "Assuming SSE 4.1 run-time support!"
  96. ret.mCaps |= CPU_CAP_SSE | CPU_CAP_SSE2 | CPU_CAP_SSE3 | CPU_CAP_SSE4_1;
  97. #elif defined(HAVE_SSE3)
  98. #warning "Assuming SSE 3 run-time support!"
  99. ret.mCaps |= CPU_CAP_SSE | CPU_CAP_SSE2 | CPU_CAP_SSE3;
  100. #elif defined(HAVE_SSE2)
  101. #warning "Assuming SSE 2 run-time support!"
  102. ret.mCaps |= CPU_CAP_SSE | CPU_CAP_SSE2;
  103. #elif defined(HAVE_SSE)
  104. #warning "Assuming SSE run-time support!"
  105. ret.mCaps |= CPU_CAP_SSE;
  106. #endif
  107. #endif /* CAN_GET_CPUID */
  108. #ifdef HAVE_NEON
  109. #ifdef __ARM_NEON
  110. ret.mCaps |= CPU_CAP_NEON;
  111. #elif defined(_WIN32) && (defined(_M_ARM) || defined(_M_ARM64))
  112. if(IsProcessorFeaturePresent(PF_ARM_NEON_INSTRUCTIONS_AVAILABLE))
  113. ret.mCaps |= CPU_CAP_NEON;
  114. #else
  115. #warning "Assuming NEON run-time support!"
  116. ret.mCaps |= CPU_CAP_NEON;
  117. #endif
  118. #endif
  119. return al::make_optional(ret);
  120. }