From e87cd16c459f5b59d7db465e3de2db617589d273 Mon Sep 17 00:00:00 2001 From: Lukas Fittl Date: Tue, 10 Mar 2026 23:38:41 -0700 Subject: [PATCH v11 1/7] Refactor handling of x86 CPUID instructions Introduce two helpers for CPUID, pg_cpuid and pg_cpuid_subleaf that wrap the platform specific __get_cpuid/__cpuid and __get_cpuid_count/__cpuidex functions. Additionally, introduce the CPUIDResult struct to make code working with CPUID easier to read by referencing the register name (e.g. ECX) instead of a numeric index. Author: Lukas Fittl Suggested-By: John Naylor Reviewed-by: Discussion: --- src/port/pg_cpu_x86.c | 70 ++++++++++++++++++++++---------- src/tools/pgindent/typedefs.list | 1 + 2 files changed, 49 insertions(+), 22 deletions(-) diff --git a/src/port/pg_cpu_x86.c b/src/port/pg_cpu_x86.c index 7575838245c..0fe4753eecc 100644 --- a/src/port/pg_cpu_x86.c +++ b/src/port/pg_cpu_x86.c @@ -53,6 +53,44 @@ mask_available(uint32 value, uint32 mask) return (value & mask) == mask; } +/* General purpose registers used by CPUID */ +typedef struct CPUIDResult +{ + unsigned int eax; + unsigned int ebx; + unsigned int ecx; + unsigned int edx; +} CPUIDResult; + +StaticAssertDecl(sizeof(CPUIDResult) == 4 * sizeof(unsigned int), + "CPUIDResult must have no padding"); + +static inline void +pg_cpuid(int leaf, CPUIDResult *r) +{ +#if defined(HAVE__GET_CPUID) + __get_cpuid(leaf, &r->eax, &r->ebx, &r->ecx, &r->edx); +#elif defined(HAVE__CPUID) + __cpuid((int *) r, leaf); +#else +#error cpuid instruction not available +#endif +} + +static inline bool +pg_cpuid_subleaf(int leaf, int subleaf, CPUIDResult *r) +{ +#if defined(HAVE__GET_CPUID_COUNT) + return __get_cpuid_count(leaf, subleaf, &r->eax, &r->ebx, &r->ecx, &r->edx) == 1; +#elif defined(HAVE__CPUIDEX) + __cpuidex((int *) r, leaf, subleaf); + return true; +#else + memset(r, 0, sizeof(CPUIDResult)); + return false; +#endif +} + /* * Parse the CPU ID info for runtime checks. */ @@ -62,33 +100,21 @@ pg_attribute_target("xsave") void set_x86_features(void) { - unsigned int exx[4] = {0, 0, 0, 0}; + CPUIDResult r = {0}; -#if defined(HAVE__GET_CPUID) - __get_cpuid(1, &exx[0], &exx[1], &exx[2], &exx[3]); -#elif defined(HAVE__CPUID) - __cpuid(exx, 1); -#else -#error cpuid instruction not available -#endif + pg_cpuid(0x01, &r); - X86Features[PG_SSE4_2] = exx[2] >> 20 & 1; - X86Features[PG_POPCNT] = exx[2] >> 23 & 1; + X86Features[PG_SSE4_2] = r.ecx >> 20 & 1; + X86Features[PG_POPCNT] = r.ecx >> 23 & 1; /* All these features depend on OSXSAVE */ - if (exx[2] & (1 << 27)) + if (r.ecx & (1 << 27)) { uint32 xcr0_val = 0; /* second cpuid call on leaf 7 to check extended AVX-512 support */ - memset(exx, 0, 4 * sizeof(exx[0])); - -#if defined(HAVE__GET_CPUID_COUNT) - __get_cpuid_count(7, 0, &exx[0], &exx[1], &exx[2], &exx[3]); -#elif defined(HAVE__CPUIDEX) - __cpuidex(exx, 7, 0); -#endif + pg_cpuid_subleaf(0x07, 0, &r); #ifdef HAVE_XSAVE_INTRINSICS /* get value of Extended Control Register */ @@ -99,11 +125,11 @@ set_x86_features(void) if (mask_available(xcr0_val, XMM | YMM | OPMASK | ZMM0_15 | ZMM16_31)) { - X86Features[PG_AVX512_BW] = exx[1] >> 30 & 1; - X86Features[PG_AVX512_VL] = exx[1] >> 31 & 1; + X86Features[PG_AVX512_BW] = r.ebx >> 30 & 1; + X86Features[PG_AVX512_VL] = r.ebx >> 31 & 1; - X86Features[PG_AVX512_VPCLMULQDQ] = exx[2] >> 10 & 1; - X86Features[PG_AVX512_VPOPCNTDQ] = exx[2] >> 14 & 1; + X86Features[PG_AVX512_VPCLMULQDQ] = r.ecx >> 10 & 1; + X86Features[PG_AVX512_VPOPCNTDQ] = r.ecx >> 14 & 1; } } diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list index 3da19d41413..489defe7362 100644 --- a/src/tools/pgindent/typedefs.list +++ b/src/tools/pgindent/typedefs.list @@ -549,6 +549,7 @@ CostSelector Counters CoverExt CoverPos +CPUIDResult CreateAmStmt CreateCastStmt CreateConversionStmt -- 2.47.1