Age Owner Branch data TLA 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
15 john.naylor@postgres 51 :GNC 1508 : mask_available(uint32 value, uint32 mask)
52 : : {
53 : 1508 : 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
16 63 : 1508 : set_x86_features(void)
64 : : {
343 65 : 1508 : unsigned int exx[4] = {0, 0, 0, 0};
66 : :
67 : : #if defined(HAVE__GET_CPUID)
68 : 1508 : __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 : :
16 75 : 1508 : X86Features[PG_SSE4_2] = exx[2] >> 20 & 1;
76 : 1508 : X86Features[PG_POPCNT] = exx[2] >> 23 & 1;
77 : :
78 : : /* All these features depend on OSXSAVE */
79 [ + - ]: 1508 : if (exx[2] & (1 << 27))
80 : : {
15 81 : 1508 : uint32 xcr0_val = 0;
82 : :
83 : : /* second cpuid call on leaf 7 to check extended AVX-512 support */
84 : :
16 85 : 1508 : memset(exx, 0, 4 * sizeof(exx[0]));
86 : :
87 : : #if defined(HAVE__GET_CPUID_COUNT)
88 : 1508 : __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 */
15 95 : 1508 : xcr0_val = _xgetbv(0);
96 : : #endif
97 : :
98 : : /* Are ZMM registers enabled? */
99 [ - + ]: 1508 : if (mask_available(xcr0_val, XMM | YMM |
100 : : OPMASK | ZMM0_15 | ZMM16_31))
101 : : {
16 john.naylor@postgres 102 :UNC 0 : X86Features[PG_AVX512_BW] = exx[1] >> 30 & 1;
103 : 0 : X86Features[PG_AVX512_VL] = exx[1] >> 31 & 1;
104 : :
105 : 0 : X86Features[PG_AVX512_VPCLMULQDQ] = exx[2] >> 10 & 1;
106 : 0 : X86Features[PG_AVX512_VPOPCNTDQ] = exx[2] >> 14 & 1;
107 : : }
108 : : }
109 : :
16 john.naylor@postgres 110 :GNC 1508 : X86Features[INIT_PG_X86] = true;
3988 heikki.linnakangas@i 111 : 1508 : }
112 : :
113 : : #endif /* defined(USE_SSE2) || defined(__i386__) */
|