• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * x86 feature check
3  *
4  * Copyright (C) 2013 Intel Corporation. All rights reserved.
5  * Author:
6  *  Jim Kukunas
7  *
8  * For conditions of distribution and use, see copyright notice in zlib.h
9  */
10 
11 #include "../../zutil.h"
12 
13 #ifdef _MSC_VER
14 #  include <intrin.h>
15 #else
16 // Newer versions of GCC and clang come with cpuid.h
17 #  include <cpuid.h>
18 #endif
19 
20 Z_INTERNAL int x86_cpu_has_avx2;
21 Z_INTERNAL int x86_cpu_has_sse2;
22 Z_INTERNAL int x86_cpu_has_ssse3;
23 Z_INTERNAL int x86_cpu_has_sse42;
24 Z_INTERNAL int x86_cpu_has_pclmulqdq;
25 Z_INTERNAL int x86_cpu_has_tzcnt;
26 
cpuid(int info,unsigned * eax,unsigned * ebx,unsigned * ecx,unsigned * edx)27 static void cpuid(int info, unsigned* eax, unsigned* ebx, unsigned* ecx, unsigned* edx) {
28 #ifdef _MSC_VER
29     unsigned int registers[4];
30     __cpuid((int *)registers, info);
31 
32     *eax = registers[0];
33     *ebx = registers[1];
34     *ecx = registers[2];
35     *edx = registers[3];
36 #else
37     __cpuid(info, *eax, *ebx, *ecx, *edx);
38 #endif
39 }
40 
cpuidex(int info,int subinfo,unsigned * eax,unsigned * ebx,unsigned * ecx,unsigned * edx)41 static void cpuidex(int info, int subinfo, unsigned* eax, unsigned* ebx, unsigned* ecx, unsigned* edx) {
42 #ifdef _MSC_VER
43     unsigned int registers[4];
44     __cpuidex((int *)registers, info, subinfo);
45 
46     *eax = registers[0];
47     *ebx = registers[1];
48     *ecx = registers[2];
49     *edx = registers[3];
50 #else
51     __cpuid_count(info, subinfo, *eax, *ebx, *ecx, *edx);
52 #endif
53 }
54 
x86_check_features(void)55 void Z_INTERNAL x86_check_features(void) {
56     unsigned eax, ebx, ecx, edx;
57     unsigned maxbasic;
58 
59     cpuid(0, &maxbasic, &ebx, &ecx, &edx);
60 
61     cpuid(1 /*CPU_PROCINFO_AND_FEATUREBITS*/, &eax, &ebx, &ecx, &edx);
62 
63     x86_cpu_has_sse2 = edx & 0x4000000;
64     x86_cpu_has_ssse3 = ecx & 0x200;
65     x86_cpu_has_sse42 = ecx & 0x100000;
66     x86_cpu_has_pclmulqdq = ecx & 0x2;
67 
68     if (maxbasic >= 7) {
69         cpuidex(7, 0, &eax, &ebx, &ecx, &edx);
70 
71         // check BMI1 bit
72         // 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
73         x86_cpu_has_tzcnt = ebx & 0x8;
74         // check AVX2 bit
75         x86_cpu_has_avx2 = ebx & 0x20;
76     } else {
77         x86_cpu_has_tzcnt = 0;
78         x86_cpu_has_avx2 = 0;
79     }
80 }
81