Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * pg_cpu_x86.c
4 : * Runtime CPU feature detection for x86
5 : *
6 : * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
7 : * Portions Copyright (c) 1994, Regents of the University of California
8 : *
9 : *
10 : * IDENTIFICATION
11 : * src/port/pg_cpu_x86.c
12 : *
13 : *-------------------------------------------------------------------------
14 : */
15 :
16 : #include "c.h"
17 :
18 : #if defined(USE_SSE2) || defined(__i386__)
19 :
20 : #if defined(HAVE__GET_CPUID) || defined(HAVE__GET_CPUID_COUNT)
21 : #include <cpuid.h>
22 : #endif
23 :
24 : #if defined(HAVE__CPUID) || defined(HAVE__CPUIDEX)
25 : #include <intrin.h>
26 : #endif
27 :
28 : #ifdef HAVE_XSAVE_INTRINSICS
29 : #include <immintrin.h>
30 : #endif
31 :
32 : #include "port/pg_cpu.h"
33 :
34 : /*
35 : * XSAVE state component bits that we need
36 : *
37 : * https://www.intel.com/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-software-developer-vol-1-manual.pdf
38 : * Chapter "MANAGING STATE USING THE XSAVE FEATURE SET"
39 : */
40 : #define XMM (1<<1)
41 : #define YMM (1<<2)
42 : #define OPMASK (1<<5)
43 : #define ZMM0_15 (1<<6)
44 : #define ZMM16_31 (1<<7)
45 :
46 :
47 : /* array indexed by enum X86FeatureId */
48 : bool X86Features[X86FeaturesSize] = {0};
49 :
50 : static bool
51 1501 : mask_available(uint32 value, uint32 mask)
52 : {
53 1501 : return (value & mask) == mask;
54 : }
55 :
56 : /*
57 : * Parse the CPU ID info for runtime checks.
58 : */
59 : #ifdef HAVE_XSAVE_INTRINSICS
60 : pg_attribute_target("xsave")
61 : #endif
62 : void
63 1501 : set_x86_features(void)
64 : {
65 1501 : unsigned int exx[4] = {0, 0, 0, 0};
66 :
67 : #if defined(HAVE__GET_CPUID)
68 1501 : __get_cpuid(1, &exx[0], &exx[1], &exx[2], &exx[3]);
69 : #elif defined(HAVE__CPUID)
70 : __cpuid(exx, 1);
71 : #else
72 : #error cpuid instruction not available
73 : #endif
74 :
75 1501 : X86Features[PG_SSE4_2] = exx[2] >> 20 & 1;
76 1501 : X86Features[PG_POPCNT] = exx[2] >> 23 & 1;
77 :
78 : /* All these features depend on OSXSAVE */
79 1501 : if (exx[2] & (1 << 27))
80 : {
81 1501 : uint32 xcr0_val = 0;
82 :
83 : /* second cpuid call on leaf 7 to check extended AVX-512 support */
84 :
85 1501 : memset(exx, 0, 4 * sizeof(exx[0]));
86 :
87 : #if defined(HAVE__GET_CPUID_COUNT)
88 1501 : __get_cpuid_count(7, 0, &exx[0], &exx[1], &exx[2], &exx[3]);
89 : #elif defined(HAVE__CPUIDEX)
90 : __cpuidex(exx, 7, 0);
91 : #endif
92 :
93 : #ifdef HAVE_XSAVE_INTRINSICS
94 : /* get value of Extended Control Register */
95 1501 : xcr0_val = _xgetbv(0);
96 : #endif
97 :
98 : /* Are ZMM registers enabled? */
99 1501 : if (mask_available(xcr0_val, XMM | YMM |
100 : OPMASK | ZMM0_15 | ZMM16_31))
101 : {
102 1501 : X86Features[PG_AVX512_BW] = exx[1] >> 30 & 1;
103 1501 : X86Features[PG_AVX512_VL] = exx[1] >> 31 & 1;
104 :
105 1501 : X86Features[PG_AVX512_VPCLMULQDQ] = exx[2] >> 10 & 1;
106 1501 : X86Features[PG_AVX512_VPOPCNTDQ] = exx[2] >> 14 & 1;
107 : }
108 : }
109 :
110 1501 : X86Features[INIT_PG_X86] = true;
111 1501 : }
112 :
113 : #endif /* defined(USE_SSE2) || defined(__i386__) */
|