96 lines
2.4 KiB
C
96 lines
2.4 KiB
C
/*-------------------------------------------------------------------------
|
|
*
|
|
* pg_crc32c_armv8_choose.c
|
|
* Choose between ARMv8 and software CRC-32C implementation.
|
|
*
|
|
* On first call, checks if the CPU we're running on supports the ARMv8
|
|
* CRC Extension. If it does, use the special instructions for CRC-32C
|
|
* computation. Otherwise, fall back to the pure software implementation
|
|
* (slicing-by-8).
|
|
*
|
|
* Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group
|
|
* Portions Copyright (c) 1994, Regents of the University of California
|
|
*
|
|
*
|
|
* IDENTIFICATION
|
|
* src/port/pg_crc32c_armv8_choose.c
|
|
*
|
|
*-------------------------------------------------------------------------
|
|
*/
|
|
|
|
#ifndef FRONTEND
|
|
#include "postgres.h"
|
|
#else
|
|
#include "postgres_fe.h"
|
|
#endif
|
|
|
|
#include <setjmp.h>
|
|
#include <signal.h>
|
|
|
|
#include "port/pg_crc32c.h"
|
|
|
|
|
|
static sigjmp_buf illegal_instruction_jump;
|
|
|
|
/*
|
|
* Probe by trying to execute pg_comp_crc32c_armv8(). If the instruction
|
|
* isn't available, we expect to get SIGILL, which we can trap.
|
|
*/
|
|
static void
|
|
illegal_instruction_handler(SIGNAL_ARGS)
|
|
{
|
|
siglongjmp(illegal_instruction_jump, 1);
|
|
}
|
|
|
|
static bool
|
|
pg_crc32c_armv8_available(void)
|
|
{
|
|
uint64 data = 42;
|
|
int result;
|
|
|
|
/*
|
|
* Be careful not to do anything that might throw an error while we have
|
|
* the SIGILL handler set to a nonstandard value.
|
|
*/
|
|
pqsignal(SIGILL, illegal_instruction_handler);
|
|
if (sigsetjmp(illegal_instruction_jump, 1) == 0)
|
|
{
|
|
/* Rather than hard-wiring an expected result, compare to SB8 code */
|
|
result = (pg_comp_crc32c_armv8(0, &data, sizeof(data)) ==
|
|
pg_comp_crc32c_sb8(0, &data, sizeof(data)));
|
|
}
|
|
else
|
|
{
|
|
/* We got the SIGILL trap */
|
|
result = -1;
|
|
}
|
|
pqsignal(SIGILL, SIG_DFL);
|
|
|
|
#ifndef FRONTEND
|
|
/* We don't expect this case, so complain loudly */
|
|
if (result == 0)
|
|
elog(ERROR, "crc32 hardware and software results disagree");
|
|
|
|
elog(DEBUG1, "using armv8 crc32 hardware = %d", (result > 0));
|
|
#endif
|
|
|
|
return (result > 0);
|
|
}
|
|
|
|
/*
|
|
* This gets called on the first call. It replaces the function pointer
|
|
* so that subsequent calls are routed directly to the chosen implementation.
|
|
*/
|
|
static pg_crc32c
|
|
pg_comp_crc32c_choose(pg_crc32c crc, const void *data, size_t len)
|
|
{
|
|
if (pg_crc32c_armv8_available())
|
|
pg_comp_crc32c = pg_comp_crc32c_armv8;
|
|
else
|
|
pg_comp_crc32c = pg_comp_crc32c_sb8;
|
|
|
|
return pg_comp_crc32c(crc, data, len);
|
|
}
|
|
|
|
pg_crc32c (*pg_comp_crc32c) (pg_crc32c crc, const void *data, size_t len) = pg_comp_crc32c_choose;
|