x86_features.c 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  1. /* x86_features.c - x86 feature check
  2. *
  3. * Copyright (C) 2013 Intel Corporation. All rights reserved.
  4. * Author:
  5. * Jim Kukunas
  6. *
  7. * For conditions of distribution and use, see copyright notice in zlib.h
  8. */
  9. #include "zbuild.h"
  10. #include "x86_features.h"
  11. #ifdef _MSC_VER
  12. # include <intrin.h>
  13. #else
  14. // Newer versions of GCC and clang come with cpuid.h
  15. # include <cpuid.h>
  16. # ifdef X86_HAVE_XSAVE_INTRIN
  17. # if __GNUC__ == 8
  18. # include <xsaveintrin.h>
  19. # else
  20. # include <immintrin.h>
  21. # endif
  22. # endif
  23. #endif
  24. #include <string.h>
  25. static inline void cpuid(int info, unsigned* eax, unsigned* ebx, unsigned* ecx, unsigned* edx) {
  26. #ifdef _MSC_VER
  27. unsigned int registers[4];
  28. __cpuid((int *)registers, info);
  29. *eax = registers[0];
  30. *ebx = registers[1];
  31. *ecx = registers[2];
  32. *edx = registers[3];
  33. #else
  34. *eax = *ebx = *ecx = *edx = 0;
  35. __cpuid(info, *eax, *ebx, *ecx, *edx);
  36. #endif
  37. }
  38. static inline void cpuidex(int info, int subinfo, unsigned* eax, unsigned* ebx, unsigned* ecx, unsigned* edx) {
  39. #ifdef _MSC_VER
  40. unsigned int registers[4];
  41. __cpuidex((int *)registers, info, subinfo);
  42. *eax = registers[0];
  43. *ebx = registers[1];
  44. *ecx = registers[2];
  45. *edx = registers[3];
  46. #else
  47. *eax = *ebx = *ecx = *edx = 0;
  48. __cpuid_count(info, subinfo, *eax, *ebx, *ecx, *edx);
  49. #endif
  50. }
  51. static inline uint64_t xgetbv(unsigned int xcr) {
  52. #if defined(_MSC_VER) || defined(X86_HAVE_XSAVE_INTRIN)
  53. return _xgetbv(xcr);
  54. #else
  55. uint32_t eax, edx;
  56. __asm__ ( ".byte 0x0f, 0x01, 0xd0" : "=a"(eax), "=d"(edx) : "c"(xcr));
  57. return (uint64_t)(edx) << 32 | eax;
  58. #endif
  59. }
  60. void Z_INTERNAL x86_check_features(struct x86_cpu_features *features) {
  61. unsigned eax, ebx, ecx, edx;
  62. unsigned maxbasic;
  63. cpuid(0, &maxbasic, &ebx, &ecx, &edx);
  64. cpuid(1 /*CPU_PROCINFO_AND_FEATUREBITS*/, &eax, &ebx, &ecx, &edx);
  65. features->has_sse2 = edx & 0x4000000;
  66. features->has_ssse3 = ecx & 0x200;
  67. features->has_sse42 = ecx & 0x100000;
  68. features->has_pclmulqdq = ecx & 0x2;
  69. if (ecx & 0x08000000) {
  70. uint64_t xfeature = xgetbv(0);
  71. features->has_os_save_ymm = ((xfeature & 0x06) == 0x06);
  72. features->has_os_save_zmm = ((xfeature & 0xe6) == 0xe6);
  73. }
  74. if (maxbasic >= 7) {
  75. cpuidex(7, 0, &eax, &ebx, &ecx, &edx);
  76. // check BMI1 bit
  77. // Reference: https://software.intel.com/sites/default/files/article/405250/how-to-detect-new-instruction-support-in-the-4th-generation-intel-core-processor-family.pdf
  78. features->has_vpclmulqdq = ecx & 0x400;
  79. // check AVX2 bit if the OS supports saving YMM registers
  80. if (features->has_os_save_ymm) {
  81. features->has_avx2 = ebx & 0x20;
  82. }
  83. // check AVX512 bits if the OS supports saving ZMM registers
  84. if (features->has_os_save_zmm) {
  85. features->has_avx512f = ebx & 0x00010000;
  86. if (features->has_avx512f) {
  87. // According to the Intel Software Developer's Manual, AVX512F must be enabled too in order to enable
  88. // AVX512(DQ,BW,VL).
  89. features->has_avx512dq = ebx & 0x00020000;
  90. features->has_avx512bw = ebx & 0x40000000;
  91. features->has_avx512vl = ebx & 0x80000000;
  92. }
  93. features->has_avx512_common = features->has_avx512f && features->has_avx512dq && features->has_avx512bw \
  94. && features->has_avx512vl;
  95. features->has_avx512vnni = ecx & 0x800;
  96. }
  97. }
  98. }