v9-0005-Move-all-cpuid-checks-to-one-location.patch
application/octet-stream
Filename: v9-0005-Move-all-cpuid-checks-to-one-location.patch
Type: application/octet-stream
Part: 4
Patch
Same data as JSON:
GET /api/v1/attachments/:id/patch
the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes.
API reference →
Format: format-patch
Series: patch v9-0005
Subject: Move all cpuid checks to one location
| File | + | − |
|---|---|---|
| configure | 2 | 2 |
| configure.ac | 2 | 2 |
| src/include/port/pg_cpucap.h | 22 | 10 |
| src/include/port/pg_crc32c.h | 4 | 2 |
| src/port/Makefile | 0 | 2 |
| src/port/meson.build | 0 | 12 |
| src/port/pg_bitutils.c | 2 | 18 |
| src/port/pg_cpucap_arm.c | 0 | 119 |
| src/port/pg_cpucap.c | 166 | 7 |
| src/port/pg_cpucap_x86.c | 0 | 75 |
| src/port/pg_crc32c_sse42.c | 2 | 1 |
| src/port/pg_popcount_avx512.c | 3 | 68 |
From aa515c0aed54d753e710d381a2254679cc4410e4 Mon Sep 17 00:00:00 2001
From: Raghuveer Devulapalli <raghuveer.devulapalli@intel.com>
Date: Tue, 25 Feb 2025 12:54:43 -0800
Subject: [PATCH v9 5/5] Move all cpuid checks to one location
---
configure | 4 +-
configure.ac | 4 +-
src/include/port/pg_cpucap.h | 32 +++++--
src/include/port/pg_crc32c.h | 6 +-
src/port/Makefile | 2 -
src/port/meson.build | 12 ---
src/port/pg_bitutils.c | 20 +---
src/port/pg_cpucap.c | 173 ++++++++++++++++++++++++++++++++--
src/port/pg_cpucap_arm.c | 119 -----------------------
src/port/pg_cpucap_x86.c | 75 ---------------
src/port/pg_crc32c_sse42.c | 3 +-
src/port/pg_popcount_avx512.c | 71 +-------------
12 files changed, 203 insertions(+), 318 deletions(-)
delete mode 100644 src/port/pg_cpucap_arm.c
delete mode 100644 src/port/pg_cpucap_x86.c
diff --git a/configure b/configure
index 0d31e6a236..172c93896c 100755
--- a/configure
+++ b/configure
@@ -17360,7 +17360,7 @@ else
$as_echo "#define USE_SSE42_CRC32C_WITH_RUNTIME_CHECK 1" >>confdefs.h
- PG_CRC32C_OBJS="pg_crc32c_sse42.o pg_crc32c_sb8.o
+ PG_CRC32C_OBJS="pg_crc32c_sse42.o pg_crc32c_sb8.o"
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: SSE 4.2 with runtime check" >&5
$as_echo "SSE 4.2 with runtime check" >&6; }
else
@@ -17376,7 +17376,7 @@ $as_echo "ARMv8 CRC instructions" >&6; }
$as_echo "#define USE_ARMV8_CRC32C_WITH_RUNTIME_CHECK 1" >>confdefs.h
- PG_CRC32C_OBJS="pg_crc32c_armv8.o pg_crc32c_sb8.o
+ PG_CRC32C_OBJS="pg_crc32c_armv8.o pg_crc32c_sb8.o"
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: ARMv8 CRC instructions with runtime check" >&5
$as_echo "ARMv8 CRC instructions with runtime check" >&6; }
else
diff --git a/configure.ac b/configure.ac
index 60d30f855d..c7bfad98ac 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2115,7 +2115,7 @@ if test x"$USE_SSE42_CRC32C" = x"1"; then
else
if test x"$USE_SSE42_CRC32C_WITH_RUNTIME_CHECK" = x"1"; then
AC_DEFINE(USE_SSE42_CRC32C_WITH_RUNTIME_CHECK, 1, [Define to 1 to use Intel SSE 4.2 CRC instructions with a runtime check.])
- PG_CRC32C_OBJS="pg_crc32c_sse42.o pg_crc32c_sb8.o
+ PG_CRC32C_OBJS="pg_crc32c_sse42.o pg_crc32c_sb8.o"
AC_MSG_RESULT(SSE 4.2 with runtime check)
else
if test x"$USE_ARMV8_CRC32C" = x"1"; then
@@ -2125,7 +2125,7 @@ else
else
if test x"$USE_ARMV8_CRC32C_WITH_RUNTIME_CHECK" = x"1"; then
AC_DEFINE(USE_ARMV8_CRC32C_WITH_RUNTIME_CHECK, 1, [Define to 1 to use ARMv8 CRC Extension with a runtime check.])
- PG_CRC32C_OBJS="pg_crc32c_armv8.o pg_crc32c_sb8.o
+ PG_CRC32C_OBJS="pg_crc32c_armv8.o pg_crc32c_sb8.o"
AC_MSG_RESULT(ARMv8 CRC instructions with runtime check)
else
if test x"$USE_LOONGARCH_CRC32C" = x"1"; then
diff --git a/src/include/port/pg_cpucap.h b/src/include/port/pg_cpucap.h
index af3fabfcff..d623db43e4 100644
--- a/src/include/port/pg_cpucap.h
+++ b/src/include/port/pg_cpucap.h
@@ -14,17 +14,29 @@
#ifndef PG_CPUCAP_H
#define PG_CPUCAP_H
-#define PGCPUCAP_INIT (1 << 0)
-#define PGCPUCAP_POPCNT (1 << 1)
-#define PGCPUCAP_VPOPCNT (1 << 2)
-#define PGCPUCAP_CRC32C (1 << 3)
-#define PGCPUCAP_CLMUL (1 << 4)
+enum pg_cpucap__
+{
+ PG_CPU_FEATURE_INIT = 0,
+ // X86
+ PG_CPU_FEATURE_SSE42 = 1,
+ PG_CPU_FEATURE_POPCNT = 2,
+ PG_CPU_FEATURE_PCLMUL = 3,
-extern PGDLLIMPORT uint32 pg_cpucap;
-extern void pg_cpucap_initialize(void);
+ /* SKX: */
+ PG_CPU_FEATURE_AVX512F = 30,
+ PG_CPU_FEATURE_AVX512BW = 31,
+
+ /* ICX */
+ PG_CPU_FEATURE_AVX512VPOPCNTDQ = 40,
+
+ // ARM
+ PG_CPU_FEATURE_ARMV8_CRC32C = 100,
-/* arch-specific functions private to src/port */
-extern void pg_cpucap_crc32c(void);
-extern void pg_cpucap_clmul(void);
+ PG_CPU_FEATURE_MAX
+};
+
+
+extern void pg_cpucap_initialize(void);
+bool pg_cpu_have(int feature_id);
#endif /* PG_CPUCAP_H */
diff --git a/src/include/port/pg_crc32c.h b/src/include/port/pg_crc32c.h
index 4f0ebb9923..41b648bea6 100644
--- a/src/include/port/pg_crc32c.h
+++ b/src/include/port/pg_crc32c.h
@@ -48,6 +48,7 @@ typedef uint32 pg_crc32c;
((crc) = pg_comp_crc32c_dispatch((crc), (data), (len)))
#define COMP_CRC32C_HW(crc, data, len) \
((crc) = pg_comp_crc32c_sse42((crc), (data), (len)))
+#define PGCPUCAP_CRC32C pg_cpu_have(PG_CPU_FEATURE_SSE42)
#define FIN_CRC32C(crc) ((crc) ^= 0xFFFFFFFF)
#if defined(USE_SSE42_CRC32C)
@@ -66,6 +67,7 @@ extern pg_crc32c pg_comp_crc32c_sse42(pg_crc32c crc, const void *data, size_t le
((crc) = pg_comp_crc32c_dispatch((crc), (data), (len)))
#define COMP_CRC32C_HW(crc, data, len) \
((crc) = pg_comp_crc32c_armv8((crc), (data), (len)))
+#define PGCPUCAP_CRC32C pg_cpu_have(PG_CPU_FEATURE_ARMV8_CRC32C)
#define FIN_CRC32C(crc) ((crc) ^= 0xFFFFFFFF)
#if defined(USE_ARMV8_CRC32C)
@@ -125,13 +127,13 @@ pg_comp_crc32c_dispatch(pg_crc32c crc, const void *data, size_t len)
*/
// WIP: how to best intialize in frontend?
#ifndef FRONTEND
- Assert(pg_cpucap & PGCPUCAP_INIT);
+ Assert(pg_cpu_have(PG_CPU_FEATURE) == 1);
#endif
#if defined(HAVE_CRC_COMPTIME)
return COMP_CRC32C_HW(crc, data, len);
#else
- if (pg_cpucap & PGCPUCAP_CRC32C)
+ if (PGCPUCAP_CRC32C)
return COMP_CRC32C_HW(crc, data, len);
else
return pg_comp_crc32c_sb8(crc, data, len);
diff --git a/src/port/Makefile b/src/port/Makefile
index 1fc03713b3..5a05179e92 100644
--- a/src/port/Makefile
+++ b/src/port/Makefile
@@ -45,8 +45,6 @@ OBJS = \
path.o \
pg_bitutils.o \
pg_cpucap.o \
- pg_cpucap_x86.o \
- pg_cpucap_arm.o \
pg_popcount_avx512.o \
pg_strong_random.o \
pgcheckdir.o \
diff --git a/src/port/meson.build b/src/port/meson.build
index baa8e16200..922ab1ad73 100644
--- a/src/port/meson.build
+++ b/src/port/meson.build
@@ -78,18 +78,6 @@ if host_system != 'windows'
replace_funcs_neg += [['pthread_barrier_wait']]
endif
-# arch-specific runtime checks
-if host_cpu == 'x86' or host_cpu == 'x86_64'
- pgport_sources += files(
- 'pg_cpucap_x86.c'
- )
-
-elif host_cpu == 'arm' or host_cpu == 'aarch64'
- pgport_sources += files(
- 'pg_cpucap_arm.c'
- )
-endif
-
# Replacement functionality to be built if corresponding configure symbol
# is true
replace_funcs_pos = [
diff --git a/src/port/pg_bitutils.c b/src/port/pg_bitutils.c
index 5677525693..4cf05f55a6 100644
--- a/src/port/pg_bitutils.c
+++ b/src/port/pg_bitutils.c
@@ -12,14 +12,8 @@
*/
#include "c.h"
-#ifdef HAVE__GET_CPUID
-#include <cpuid.h>
-#endif
-#ifdef HAVE__CPUID
-#include <intrin.h>
-#endif
-
#include "port/pg_bitutils.h"
+#include "port/pg_cpucap.h"
/*
@@ -133,17 +127,7 @@ uint64 (*pg_popcount_masked_optimized) (const char *buf, int bytes, bits8 mask)
static bool
pg_popcount_available(void)
{
- unsigned int exx[4] = {0, 0, 0, 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
-
- return (exx[2] & (1 << 23)) != 0; /* POPCNT */
+ return pg_cpu_have(PG_CPU_FEATURE_POPCNT);
}
/*
diff --git a/src/port/pg_cpucap.c b/src/port/pg_cpucap.c
index 301bd9fc2c..b1e38065c7 100644
--- a/src/port/pg_cpucap.c
+++ b/src/port/pg_cpucap.c
@@ -15,20 +15,179 @@
#include "port/pg_cpucap.h"
+#ifdef HAVE__GET_CPUID
+#include <cpuid.h>
+#endif
-/* starts uninitialized so we can detect errors of omission */
-uint32 pg_cpucap = 0;
+#ifdef HAVE__CPUID
+#include <intrin.h>
+#endif
+
+static unsigned char pg_cpucap[PG_CPU_FEATURE_MAX];
+
+#ifdef __x86_64__
+// for _xgetbv
+#include <immintrin.h>
+/*
+ * Does XGETBV say the ZMM registers are enabled?
+ *
+ * NB: Caller is responsible for verifying that xsave_available() returns true
+ * before calling this.
+ */
+#ifdef HAVE_XSAVE_INTRINSICS
+pg_attribute_target("xsave")
+#endif
+static inline bool
+zmm_regs_available(void)
+{
+#ifdef HAVE_XSAVE_INTRINSICS
+ return (_xgetbv(0) & 0xe6) == 0xe6;
+#else
+ return false;
+#endif
+}
+
+static void pg_cpuid(int leaf, int subleaf, unsigned int* exx)
+{
+#if defined(HAVE__GET_CPUID_COUNT)
+ __get_cpuid_count(leaf, subleaf, &exx[0], &exx[1], &exx[2], &exx[3]);
+#elif defined(HAVE__CPUIDEX)
+ __cpuidex(exx, leaf, subleaf);
+#else
+#error cpuid instruction not available
+#endif
+}
+
+static void
+pg_cpucap_x86(void)
+{
+ unsigned int exx[4] = {0, 0, 0, 0};
+ pg_cpuid(1, 0, exx);
+
+ pg_cpucap[PG_CPU_FEATURE_SSE42] = (exx[2] & (1 << 20)) != 0;
+ pg_cpucap[PG_CPU_FEATURE_PCLMUL] = (exx[2] & (1 << 1)) != 0;
+ pg_cpucap[PG_CPU_FEATURE_POPCNT] = (exx[2] & (1 << 23)) != 0;
+ /* osxsave */
+ if ((exx[2] & (1 << 27)) == 0) {
+ return;
+ }
+ /* avx512 os support */
+ if (zmm_regs_available()) {
+ return;
+ }
+ /* second cpuid call on leaf 7 to check extended avx512 support */
+ pg_cpuid(7, 0, exx);
+
+ pg_cpucap[PG_CPU_FEATURE_AVX512F] = (exx[1] & (1 << 16)) != 0;
+ pg_cpucap[PG_CPU_FEATURE_AVX512BW] = (exx[1] & (1 << 30)) != 0;
+ pg_cpucap[PG_CPU_FEATURE_AVX512VPOPCNTDQ] = (exx[2] & (1 << 14)) != 0;
+
+}
+#else // ARM
+static bool
+pg_crc32c_armv8_available(void)
+{
+#if defined(HAVE_ELF_AUX_INFO)
+ unsigned long value;
+
+#ifdef __aarch64__
+ return elf_aux_info(AT_HWCAP, &value, sizeof(value)) == 0 &&
+ (value & HWCAP_CRC32) != 0;
+#else
+ return elf_aux_info(AT_HWCAP2, &value, sizeof(value)) == 0 &&
+ (value & HWCAP2_CRC32) != 0;
+#endif
+#elif defined(HAVE_GETAUXVAL)
+#ifdef __aarch64__
+ return (getauxval(AT_HWCAP) & HWCAP_CRC32) != 0;
+#else
+ return (getauxval(AT_HWCAP2) & HWCAP2_CRC32) != 0;
+#endif
+#elif defined(__NetBSD__)
+ /*
+ * On NetBSD we can read the Instruction Set Attribute Registers via
+ * sysctl. For doubtless-historical reasons the sysctl interface is
+ * completely different on 64-bit than 32-bit, but the underlying
+ * registers contain the same fields.
+ */
+#define ISAR0_CRC32_BITPOS 16
+#define ISAR0_CRC32_BITWIDTH 4
+#define WIDTHMASK(w) ((1 << (w)) - 1)
+#define SYSCTL_CPU_ID_MAXSIZE 64
+
+ size_t len;
+ uint64 sysctlbuf[SYSCTL_CPU_ID_MAXSIZE];
+#if defined(__aarch64__)
+ /* We assume cpu0 is representative of all the machine's CPUs. */
+ const char *path = "machdep.cpu0.cpu_id";
+ size_t expected_len = sizeof(struct aarch64_sysctl_cpu_id);
+#define ISAR0 ((struct aarch64_sysctl_cpu_id *) sysctlbuf)->ac_aa64isar0
+#else
+ const char *path = "machdep.id_isar";
+ size_t expected_len = 6 * sizeof(int);
+#define ISAR0 ((int *) sysctlbuf)[5]
+#endif
+ uint64 fld;
+
+ /* Fetch the appropriate set of register values. */
+ len = sizeof(sysctlbuf);
+ memset(sysctlbuf, 0, len);
+ if (sysctlbyname(path, sysctlbuf, &len, NULL, 0) != 0)
+ return false; /* perhaps kernel is 64-bit and we aren't? */
+ if (len != expected_len)
+ return false; /* kernel API change? */
+
+ /* Fetch the CRC32 field from ISAR0. */
+ fld = (ISAR0 >> ISAR0_CRC32_BITPOS) & WIDTHMASK(ISAR0_CRC32_BITWIDTH);
+
+ /*
+ * Current documentation defines only the field values 0 (No CRC32) and 1
+ * (CRC32B/CRC32H/CRC32W/CRC32X/CRC32CB/CRC32CH/CRC32CW/CRC32CX). Assume
+ * that any future nonzero value will be a superset of 1.
+ */
+ return (fld != 0);
+#else
+ return false;
+#endif
+}
+
+static void
+pg_cpucap_arm(void)
+{
+ if (pg_crc32c_armv8_available()) {
+ pg_cpucap[PG_CPU_FEATURE_ARMV8_CRC32C] = 1;
+ }
+}
+#endif
+
+
+static void
+pg_cpucap_arch()
+{
+ /* WIP: configure checks */
+#ifdef __x86_64__
+ pg_cpucap_x86();
+#else // ARM:
+ pg_cpucap_arm();
+#endif
+}
/*
* This needs to be called in main() for every
* program that calls a function that dispatches
* according to CPU features.
*/
-void
-pg_cpucap_initialize(void)
+void pg_cpucap_initialize(void)
{
- pg_cpucap = PGCPUCAP_INIT;
+ /* Initialize everything to zero */
+ memset(pg_cpucap, 0, sizeof(pg_cpucap[0]) * PG_CPU_FEATURE_MAX);
+ pg_cpucap[PG_CPU_FEATURE_INIT] = 1;
+
+ pg_cpucap_arch();
+}
- pg_cpucap_crc32c();
- pg_cpucap_clmul();
+/* Access to pg_cpucap for modules that need runtime CPUID information */
+bool pg_cpu_have(int feature_id)
+{
+ return pg_cpucap[feature_id];
}
diff --git a/src/port/pg_cpucap_arm.c b/src/port/pg_cpucap_arm.c
deleted file mode 100644
index e080a5a931..0000000000
--- a/src/port/pg_cpucap_arm.c
+++ /dev/null
@@ -1,119 +0,0 @@
-/*-------------------------------------------------------------------------
- *
- * pg_cpucap_arm.c
- * Check if the CPU we're running on supports the ARMv8 CRC Extension.
- *
- * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
- * Portions Copyright (c) 1994, Regents of the University of California
- *
- *
- * IDENTIFICATION
- * src/port/pg_cpucap_arm.c
- *
- *-------------------------------------------------------------------------
- */
-
-#ifndef FRONTEND
-#include "postgres.h"
-#else
-#include "postgres_fe.h"
-#endif
-
-#if defined(HAVE_ELF_AUX_INFO) || defined(HAVE_GETAUXVAL)
-#include <sys/auxv.h>
-#if defined(__linux__) && !defined(__aarch64__) && !defined(HWCAP2_CRC32)
-#include <asm/hwcap.h>
-#endif
-#endif
-
-#if defined(__NetBSD__)
-#include <sys/sysctl.h>
-#if defined(__aarch64__)
-#include <aarch64/armreg.h>
-#endif
-#endif
-
-#include "port/pg_crc32c.h"
-
-static bool
-pg_crc32c_armv8_available(void)
-{
-#if defined(HAVE_ELF_AUX_INFO)
- unsigned long value;
-
-#ifdef __aarch64__
- return elf_aux_info(AT_HWCAP, &value, sizeof(value)) == 0 &&
- (value & HWCAP_CRC32) != 0;
-#else
- return elf_aux_info(AT_HWCAP2, &value, sizeof(value)) == 0 &&
- (value & HWCAP2_CRC32) != 0;
-#endif
-#elif defined(HAVE_GETAUXVAL)
-#ifdef __aarch64__
- return (getauxval(AT_HWCAP) & HWCAP_CRC32) != 0;
-#else
- return (getauxval(AT_HWCAP2) & HWCAP2_CRC32) != 0;
-#endif
-#elif defined(__NetBSD__)
- /*
- * On NetBSD we can read the Instruction Set Attribute Registers via
- * sysctl. For doubtless-historical reasons the sysctl interface is
- * completely different on 64-bit than 32-bit, but the underlying
- * registers contain the same fields.
- */
-#define ISAR0_CRC32_BITPOS 16
-#define ISAR0_CRC32_BITWIDTH 4
-#define WIDTHMASK(w) ((1 << (w)) - 1)
-#define SYSCTL_CPU_ID_MAXSIZE 64
-
- size_t len;
- uint64 sysctlbuf[SYSCTL_CPU_ID_MAXSIZE];
-#if defined(__aarch64__)
- /* We assume cpu0 is representative of all the machine's CPUs. */
- const char *path = "machdep.cpu0.cpu_id";
- size_t expected_len = sizeof(struct aarch64_sysctl_cpu_id);
-#define ISAR0 ((struct aarch64_sysctl_cpu_id *) sysctlbuf)->ac_aa64isar0
-#else
- const char *path = "machdep.id_isar";
- size_t expected_len = 6 * sizeof(int);
-#define ISAR0 ((int *) sysctlbuf)[5]
-#endif
- uint64 fld;
-
- /* Fetch the appropriate set of register values. */
- len = sizeof(sysctlbuf);
- memset(sysctlbuf, 0, len);
- if (sysctlbyname(path, sysctlbuf, &len, NULL, 0) != 0)
- return false; /* perhaps kernel is 64-bit and we aren't? */
- if (len != expected_len)
- return false; /* kernel API change? */
-
- /* Fetch the CRC32 field from ISAR0. */
- fld = (ISAR0 >> ISAR0_CRC32_BITPOS) & WIDTHMASK(ISAR0_CRC32_BITWIDTH);
-
- /*
- * Current documentation defines only the field values 0 (No CRC32) and 1
- * (CRC32B/CRC32H/CRC32W/CRC32X/CRC32CB/CRC32CH/CRC32CW/CRC32CX). Assume
- * that any future nonzero value will be a superset of 1.
- */
- return (fld != 0);
-#else
- return false;
-#endif
-}
-
-/*
- * Check if hardware instructions for CRC computation are available.
- */
-void
-pg_cpucap_crc32c(void)
-{
- if (pg_crc32c_armv8_available())
- pg_cpucap |= PGCPUCAP_CRC32C;
-}
-
-void
-pg_cpucap_clmul(void)
-{
- // WIP: does this even make sense?
-}
diff --git a/src/port/pg_cpucap_x86.c b/src/port/pg_cpucap_x86.c
deleted file mode 100644
index 3a62a3a582..0000000000
--- a/src/port/pg_cpucap_x86.c
+++ /dev/null
@@ -1,75 +0,0 @@
-/*-------------------------------------------------------------------------
- *
- * pg_cpucap_x86.c
- * Check if the CPU we're running on supports SSE4.2.
- *
- * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
- * Portions Copyright (c) 1994, Regents of the University of California
- *
- *
- * IDENTIFICATION
- * src/port/pg_cpucap_x86.c
- *
- *-------------------------------------------------------------------------
- */
-
-#include "c.h"
-
-#ifdef HAVE__GET_CPUID
-#include <cpuid.h>
-#endif
-
-#ifdef HAVE__CPUID
-#include <intrin.h>
-#endif
-
-#include "port/pg_cpucap.h"
-
-static bool
-pg_sse42_available(void)
-{
- unsigned int exx[4] = {0, 0, 0, 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
-
- return (exx[2] & (1 << 20)) != 0; /* SSE 4.2 */
-}
-
-static bool
-pg_pclmul_available(void)
-{
- unsigned int exx[4] = {0, 0, 0, 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
-
- return (exx[2] & (1 << 1)) != 0; /* PCLMUL */
-}
-
-/*
- * Check if hardware instructions for CRC computation are available.
- */
-void
-pg_cpucap_crc32c(void)
-{
- if (pg_sse42_available())
- pg_cpucap |= PGCPUCAP_CRC32C;
-}
-
-void
-pg_cpucap_clmul(void)
-{
- if (pg_pclmul_available())
- pg_cpucap |= PGCPUCAP_CLMUL;
-}
diff --git a/src/port/pg_crc32c_sse42.c b/src/port/pg_crc32c_sse42.c
index fc3cf0d088..7131b4a326 100644
--- a/src/port/pg_crc32c_sse42.c
+++ b/src/port/pg_crc32c_sse42.c
@@ -18,6 +18,7 @@
#include <wmmintrin.h>
#include "port/pg_crc32c.h"
+#include "port/pg_cpucap.h"
/* WIP: configure checks */
#ifdef __x86_64__
@@ -140,7 +141,7 @@ pg_comp_crc32c_sse42(pg_crc32c crc, const void *data, size_t len)
const size_t orig_len PG_USED_FOR_ASSERTS_ONLY = len;
#ifdef HAVE_PCLMUL_RUNTIME
- if (len >= PCLMUL_THRESHOLD && (pg_cpucap & PGCPUCAP_CLMUL))
+ if (len >= PCLMUL_THRESHOLD && (pg_cpu_have(PG_CPU_FEATURE_PCLMUL)))
{
return pg_comp_crc32c_pclmul(crc, data, len);
}
diff --git a/src/port/pg_popcount_avx512.c b/src/port/pg_popcount_avx512.c
index dac895a0fc..7f5846b1bd 100644
--- a/src/port/pg_popcount_avx512.c
+++ b/src/port/pg_popcount_avx512.c
@@ -14,17 +14,10 @@
#ifdef USE_AVX512_POPCNT_WITH_RUNTIME_CHECK
-#if defined(HAVE__GET_CPUID) || defined(HAVE__GET_CPUID_COUNT)
-#include <cpuid.h>
-#endif
-
#include <immintrin.h>
-#if defined(HAVE__CPUID) || defined(HAVE__CPUIDEX)
-#include <intrin.h>
-#endif
-
#include "port/pg_bitutils.h"
+#include "port/pg_cpucap.h"
/*
* It's probably unlikely that TRY_POPCNT_FAST won't be set if we are able to
@@ -33,63 +26,6 @@
*/
#ifdef TRY_POPCNT_FAST
-/*
- * Does CPUID say there's support for XSAVE instructions?
- */
-static inline bool
-xsave_available(void)
-{
- unsigned int exx[4] = {0, 0, 0, 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
- return (exx[2] & (1 << 27)) != 0; /* osxsave */
-}
-
-/*
- * Does XGETBV say the ZMM registers are enabled?
- *
- * NB: Caller is responsible for verifying that xsave_available() returns true
- * before calling this.
- */
-#ifdef HAVE_XSAVE_INTRINSICS
-pg_attribute_target("xsave")
-#endif
-static inline bool
-zmm_regs_available(void)
-{
-#ifdef HAVE_XSAVE_INTRINSICS
- return (_xgetbv(0) & 0xe6) == 0xe6;
-#else
- return false;
-#endif
-}
-
-/*
- * Does CPUID say there's support for AVX-512 popcount and byte-and-word
- * instructions?
- */
-static inline bool
-avx512_popcnt_available(void)
-{
- unsigned int exx[4] = {0, 0, 0, 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);
-#else
-#error cpuid instruction not available
-#endif
- return (exx[2] & (1 << 14)) != 0 && /* avx512-vpopcntdq */
- (exx[1] & (1 << 30)) != 0; /* avx512-bw */
-}
-
/*
* Returns true if the CPU supports the instructions required for the AVX-512
* pg_popcount() implementation.
@@ -97,9 +33,8 @@ avx512_popcnt_available(void)
bool
pg_popcount_avx512_available(void)
{
- return xsave_available() &&
- zmm_regs_available() &&
- avx512_popcnt_available();
+ return pg_cpu_have(PG_CPU_FEATURE_AVX512VPOPCNTDQ) &&
+ pg_cpu_have(PG_CPU_FEATURE_AVX512BW);
}
/*
--
2.43.0