PostgreSQL Source Code git master
pg_crc32c_armv8_choose.c
Go to the documentation of this file.
1/*-------------------------------------------------------------------------
2 *
3 * pg_crc32c_armv8_choose.c
4 * Choose between ARMv8 and software CRC-32C implementation.
5 *
6 * On first call, checks if the CPU we're running on supports the ARMv8
7 * CRC Extension. If it does, use the special instructions for CRC-32C
8 * computation. Otherwise, fall back to the pure software implementation
9 * (slicing-by-8).
10 *
11 * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
12 * Portions Copyright (c) 1994, Regents of the University of California
13 *
14 *
15 * IDENTIFICATION
16 * src/port/pg_crc32c_armv8_choose.c
17 *
18 *-------------------------------------------------------------------------
19 */
20
21#ifndef FRONTEND
22#include "postgres.h"
23#else
24#include "postgres_fe.h"
25#endif
26
27#if defined(HAVE_ELF_AUX_INFO) || defined(HAVE_GETAUXVAL)
28#include <sys/auxv.h>
29/* Ancient glibc releases don't include the HWCAPxxx macros in sys/auxv.h */
30#if defined(__linux__) && (defined(__aarch64__) ? !defined(HWCAP_CRC32) : !defined(HWCAP2_CRC32))
31#include <asm/hwcap.h>
32#endif
33#endif
34
35#if defined(__NetBSD__)
36#include <sys/sysctl.h>
37#if defined(__aarch64__)
38#include <aarch64/armreg.h>
39#endif
40#endif
41
42#include "port/pg_crc32c.h"
43
44static bool
46{
47#if defined(HAVE_ELF_AUX_INFO)
48 unsigned long value;
49
50#ifdef __aarch64__
51 return elf_aux_info(AT_HWCAP, &value, sizeof(value)) == 0 &&
52 (value & HWCAP_CRC32) != 0;
53#else
54 return elf_aux_info(AT_HWCAP2, &value, sizeof(value)) == 0 &&
55 (value & HWCAP2_CRC32) != 0;
56#endif
57#elif defined(HAVE_GETAUXVAL)
58#ifdef __aarch64__
59 return (getauxval(AT_HWCAP) & HWCAP_CRC32) != 0;
60#else
61 return (getauxval(AT_HWCAP2) & HWCAP2_CRC32) != 0;
62#endif
63#elif defined(__NetBSD__)
64 /*
65 * On NetBSD we can read the Instruction Set Attribute Registers via
66 * sysctl. For doubtless-historical reasons the sysctl interface is
67 * completely different on 64-bit than 32-bit, but the underlying
68 * registers contain the same fields.
69 */
70#define ISAR0_CRC32_BITPOS 16
71#define ISAR0_CRC32_BITWIDTH 4
72#define WIDTHMASK(w) ((1 << (w)) - 1)
73#define SYSCTL_CPU_ID_MAXSIZE 64
74
75 size_t len;
76 uint64 sysctlbuf[SYSCTL_CPU_ID_MAXSIZE];
77#if defined(__aarch64__)
78 /* We assume cpu0 is representative of all the machine's CPUs. */
79 const char *path = "machdep.cpu0.cpu_id";
80 size_t expected_len = sizeof(struct aarch64_sysctl_cpu_id);
81#define ISAR0 ((struct aarch64_sysctl_cpu_id *) sysctlbuf)->ac_aa64isar0
82#else
83 const char *path = "machdep.id_isar";
84 size_t expected_len = 6 * sizeof(int);
85#define ISAR0 ((int *) sysctlbuf)[5]
86#endif
87 uint64 fld;
88
89 /* Fetch the appropriate set of register values. */
90 len = sizeof(sysctlbuf);
91 memset(sysctlbuf, 0, len);
92 if (sysctlbyname(path, sysctlbuf, &len, NULL, 0) != 0)
93 return false; /* perhaps kernel is 64-bit and we aren't? */
94 if (len != expected_len)
95 return false; /* kernel API change? */
96
97 /* Fetch the CRC32 field from ISAR0. */
98 fld = (ISAR0 >> ISAR0_CRC32_BITPOS) & WIDTHMASK(ISAR0_CRC32_BITWIDTH);
99
100 /*
101 * Current documentation defines only the field values 0 (No CRC32) and 1
102 * (CRC32B/CRC32H/CRC32W/CRC32X/CRC32CB/CRC32CH/CRC32CW/CRC32CX). Assume
103 * that any future nonzero value will be a superset of 1.
104 */
105 return (fld != 0);
106#else
107 return false;
108#endif
109}
110
111/*
112 * This gets called on the first call. It replaces the function pointer
113 * so that subsequent calls are routed directly to the chosen implementation.
114 */
115static pg_crc32c
117{
120 else
122
123 return pg_comp_crc32c(crc, data, len);
124}
125
uint64_t uint64
Definition: c.h:542
static struct @171 value
uint32 pg_crc32c
Definition: pg_crc32c.h:38
pg_crc32c pg_comp_crc32c_sb8(pg_crc32c crc, const void *data, size_t len)
Definition: pg_crc32c_sb8.c:35
pg_crc32c pg_comp_crc32c_armv8(pg_crc32c crc, const void *data, size_t len)
pg_crc32c(* pg_comp_crc32c)(pg_crc32c crc, const void *data, size_t len)
static bool pg_crc32c_armv8_available(void)
static pg_crc32c pg_comp_crc32c_choose(pg_crc32c crc, const void *data, size_t len)
const void size_t len
const void * data
return crc