1/*-------------------------------------------------------------------------
2 *
3 * pg_crc32c_sse42_choose.c
4 * Choose between Intel SSE 4.2 and software CRC-32C implementation.
5 *
6 * On first call, checks if the CPU we're running on supports Intel SSE
7 * 4.2. If it does, use the special SSE instructions for CRC-32C
8 * computation. Otherwise, fall back to the pure software implementation
9 * (slicing-by-8).
10 *
11 * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group
12 * Portions Copyright (c) 1994, Regents of the University of California
13 *
14 *
15 * IDENTIFICATION
16 * src/port/pg_crc32c_sse42_choose.c
17 *
18 *-------------------------------------------------------------------------
19 */
20
21#include "c.h"
22
23#ifdef HAVE__GET_CPUID
24#include <cpuid.h>
25#endif
26
27#ifdef HAVE__CPUID
28#include <intrin.h>
29#endif
30
31#include "port/pg_crc32c.h"
32
33static bool
34pg_crc32c_sse42_available(void)
35{
36 unsigned int exx[4] = {0, 0, 0, 0};
37
38#if defined(HAVE__GET_CPUID)
39 __get_cpuid(1, &exx[0], &exx[1], &exx[2], &exx[3]);
40#elif defined(HAVE__CPUID)
41 __cpuid(exx, 1);
42#else
43#error cpuid instruction not available
44#endif
45
46 return (exx[2] & (1 << 20)) != 0; /* SSE 4.2 */
47}
48
49/*
50 * This gets called on the first call. It replaces the function pointer
51 * so that subsequent calls are routed directly to the chosen implementation.
52 */
53static pg_crc32c
54pg_comp_crc32c_choose(pg_crc32c crc, const void *data, size_t len)
55{
56 if (pg_crc32c_sse42_available())
57 pg_comp_crc32c = pg_comp_crc32c_sse42;
58 else
59 pg_comp_crc32c = pg_comp_crc32c_sb8;
60
61 return pg_comp_crc32c(crc, data, len);
62}
63
64pg_crc32c (*pg_comp_crc32c) (pg_crc32c crc, const void *data, size_t len) = pg_comp_crc32c_choose;
65