🛠️🐜 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.

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