1 /*-------------------------------------------------------------------------
3 * pg_crc32c_armv8_choose.c
4 * Choose between ARMv8 and software CRC-32C implementation.
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
11 * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group
12 * Portions Copyright (c) 1994, Regents of the University of California
16 * src/port/pg_crc32c_armv8_choose.c
18 *-------------------------------------------------------------------------
24 #include "postgres_fe.h"
30 #include "port/pg_crc32c.h"
33 static sigjmp_buf illegal_instruction_jump
;
36 * Probe by trying to execute pg_comp_crc32c_armv8(). If the instruction
37 * isn't available, we expect to get SIGILL, which we can trap.
40 illegal_instruction_handler(SIGNAL_ARGS
)
42 siglongjmp(illegal_instruction_jump
, 1);
46 pg_crc32c_armv8_available(void)
52 * Be careful not to do anything that might throw an error while we have
53 * the SIGILL handler set to a nonstandard value.
55 pqsignal(SIGILL
, illegal_instruction_handler
);
56 if (sigsetjmp(illegal_instruction_jump
, 1) == 0)
58 /* Rather than hard-wiring an expected result, compare to SB8 code */
59 result
= (pg_comp_crc32c_armv8(0, &data
, sizeof(data
)) ==
60 pg_comp_crc32c_sb8(0, &data
, sizeof(data
)));
64 /* We got the SIGILL trap */
67 pqsignal(SIGILL
, SIG_DFL
);
70 /* We don't expect this case, so complain loudly */
72 elog(ERROR
, "crc32 hardware and software results disagree");
74 elog(DEBUG1
, "using armv8 crc32 hardware = %d", (result
> 0));
81 * This gets called on the first call. It replaces the function pointer
82 * so that subsequent calls are routed directly to the chosen implementation.
85 pg_comp_crc32c_choose(pg_crc32c crc
, const void *data
, size_t len
)
87 if (pg_crc32c_armv8_available())
88 pg_comp_crc32c
= pg_comp_crc32c_armv8
;
90 pg_comp_crc32c
= pg_comp_crc32c_sb8
;
92 return pg_comp_crc32c(crc
, data
, len
);
95 pg_crc32c (*pg_comp_crc32c
) (pg_crc32c crc
, const void *data
, size_t len
) = pg_comp_crc32c_choose
;