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 : #ifdef _MSC_VER
21 : #include <intrin.h>
22 : #else
23 : #include <cpuid.h>
24 : #endif
25 :
26 : #ifdef HAVE_XSAVE_INTRINSICS
27 : #include <immintrin.h>
28 : #endif
29 :
30 : #include "port/pg_cpu.h"
31 :
32 : /*
33 : * XSAVE state component bits that we need
34 : *
35 : * https://www.intel.com/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-software-developer-vol-1-manual.pdf
36 : * Chapter "MANAGING STATE USING THE XSAVE FEATURE SET"
37 : */
38 : #define XMM (1<<1)
39 : #define YMM (1<<2)
40 : #define OPMASK (1<<5)
41 : #define ZMM0_15 (1<<6)
42 : #define ZMM16_31 (1<<7)
43 :
44 :
45 : /* array indexed by enum X86FeatureId */
46 : bool X86Features[X86FeaturesSize] = {0};
47 :
48 : static bool
49 3306 : mask_available(uint32 value, uint32 mask)
50 : {
51 3306 : return (value & mask) == mask;
52 : }
53 :
54 : /* Named indexes for CPUID register array */
55 : #define EAX 0
56 : #define EBX 1
57 : #define ECX 2
58 : #define EDX 3
59 :
60 : /*
61 : * Request CPUID information for the specified leaf.
62 : */
63 : static inline void
64 1653 : pg_cpuid(int leaf, unsigned int *reg)
65 : {
66 : #if defined(HAVE__GET_CPUID)
67 1653 : __get_cpuid(leaf, ®[EAX], ®[EBX], ®[ECX], ®[EDX]);
68 : #elif defined(HAVE__CPUID)
69 : __cpuid((int *) reg, leaf);
70 : #else
71 : #error cpuid instruction not available
72 : #endif
73 1653 : }
74 :
75 : /*
76 : * Request CPUID information for the specified leaf and subleaf.
77 : *
78 : * Returns true if the CPUID leaf/subleaf is supported, false otherwise.
79 : */
80 : static inline bool
81 1653 : pg_cpuid_subleaf(int leaf, int subleaf, unsigned int *reg)
82 : {
83 : #if defined(HAVE__GET_CPUID_COUNT)
84 1653 : return __get_cpuid_count(leaf, subleaf, ®[EAX], ®[EBX], ®[ECX], ®[EDX]) == 1;
85 : #elif defined(HAVE__CPUIDEX)
86 : __cpuidex((int *) reg, leaf, subleaf);
87 : return true;
88 : #else
89 : memset(reg, 0, 4 * sizeof(unsigned int));
90 : return false;
91 : #endif
92 : }
93 :
94 : /*
95 : * Parse the CPU ID info for runtime checks.
96 : */
97 : #ifdef HAVE_XSAVE_INTRINSICS
98 : pg_attribute_target("xsave")
99 : #endif
100 : void
101 1653 : set_x86_features(void)
102 : {
103 1653 : unsigned int reg[4] = {0};
104 :
105 1653 : pg_cpuid(0x01, reg);
106 :
107 1653 : X86Features[PG_SSE4_2] = reg[ECX] >> 20 & 1;
108 1653 : X86Features[PG_POPCNT] = reg[ECX] >> 23 & 1;
109 :
110 : /* leaf 7 features that depend on OSXSAVE */
111 1653 : if (reg[ECX] & (1 << 27))
112 : {
113 1653 : uint32 xcr0_val = 0;
114 :
115 1653 : pg_cpuid_subleaf(0x07, 0, reg);
116 :
117 : #ifdef HAVE_XSAVE_INTRINSICS
118 : /* get value of Extended Control Register */
119 1653 : xcr0_val = _xgetbv(0);
120 : #endif
121 :
122 : /* Are YMM registers enabled? */
123 1653 : if (mask_available(xcr0_val, XMM | YMM))
124 1653 : X86Features[PG_AVX2] = reg[EBX] >> 5 & 1;
125 :
126 : /* Are ZMM registers enabled? */
127 1653 : if (mask_available(xcr0_val, XMM | YMM |
128 : OPMASK | ZMM0_15 | ZMM16_31))
129 : {
130 1653 : X86Features[PG_AVX512_BW] = reg[EBX] >> 30 & 1;
131 1653 : X86Features[PG_AVX512_VL] = reg[EBX] >> 31 & 1;
132 :
133 1653 : X86Features[PG_AVX512_VPCLMULQDQ] = reg[ECX] >> 10 & 1;
134 1653 : X86Features[PG_AVX512_VPOPCNTDQ] = reg[ECX] >> 14 & 1;
135 : }
136 : }
137 :
138 1653 : X86Features[INIT_PG_X86] = true;
139 1653 : }
140 :
141 : #endif /* defined(USE_SSE2) || defined(__i386__) */
|