From 15f51f7fcd6a65eeaea27e49cd70cd75bde6e35d Mon Sep 17 00:00:00 2001 From: Thomas Munro Date: Wed, 2 May 2018 21:48:40 +1200 Subject: [PATCH] Use a portable way to detect ARMv8 CRC32 hardware. Commit f044d71e introduced support for ARMv8 CRC32 compiler intrinsics, but used a non-portable Linux-only interface to detect the capability at runtime. Switch to a simple probing scheme where we try it and see if SIGILL is raised. Thomas Munro Reviewed-By: Tom Lane Discussion: https://postgr.es/m/CAEepm%3D02Run-Pk3xyt%2BRV3p1N%2B7cKZxN95_MamaJw8Cnw%2BDwjQ%40mail.gmail.com --- configure | 45 ++----------------------------- configure.in | 21 ++------------- src/port/pg_crc32c_armv8_choose.c | 30 ++++++++++++++------- 3 files changed, 25 insertions(+), 71 deletions(-) diff --git a/configure b/configure index 56f18dfbc26..0aafd9c8c06 100755 --- a/configure +++ b/configure @@ -17344,46 +17344,6 @@ fi fi -# In order to detect at runtime, if the ARM CRC Extension is available, -# we will do "getauxval(AT_HWCAP) & HWCAP_CRC32". Check if we have -# everything we need for that. -for ac_func in getauxval -do : - ac_fn_c_check_func "$LINENO" "getauxval" "ac_cv_func_getauxval" -if test "x$ac_cv_func_getauxval" = xyes; then : - cat >>confdefs.h <<_ACEOF -#define HAVE_GETAUXVAL 1 -_ACEOF - -fi -done - -cat confdefs.h - <<_ACEOF >conftest.$ac_ext -/* end confdefs.h. */ - -#include -#include - -int -main () -{ - -#ifndef AT_HWCAP -#error AT_HWCAP not defined -#endif -#ifndef HWCAP_CRC32 -#error HWCAP_CRC32 not defined -#endif - - ; - return 0; -} -_ACEOF -if ac_fn_c_try_compile "$LINENO"; then : - HAVE_HWCAP_CRC32=1 -fi -rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext - # Select CRC-32C implementation. # # If we are targeting a processor that has Intel SSE 4.2 instructions, we can @@ -17414,9 +17374,8 @@ if test x"$USE_SLICING_BY_8_CRC32C" = x"" && test x"$USE_SSE42_CRC32C" = x"" && if test x"$pgac_armv8_crc32c_intrinsics" = x"yes" && test x"$CFLAGS_ARMV8_CRC32C" = x""; then USE_ARMV8_CRC32C=1 else - # ARM CRC Extension, with runtime check? The getauxval() function and - # HWCAP_CRC32 are needed for the runtime check. - if test x"$pgac_armv8_crc32c_intrinsics" = x"yes" && test x"$ac_cv_func_getauxval" = x"yes" && test x"$HAVE_HWCAP_CRC32" = x"1"; then + # ARM CRC Extension, with runtime check? + if test x"$pgac_armv8_crc32c_intrinsics" = x"yes"; then USE_ARMV8_CRC32C_WITH_RUNTIME_CHECK=1 else # fall back to slicing-by-8 algorithm, which doesn't require any diff --git a/configure.in b/configure.in index da02a56ec66..c3841d5b07f 100644 --- a/configure.in +++ b/configure.in @@ -2014,22 +2014,6 @@ if test x"$pgac_armv8_crc32c_intrinsics" != x"yes"; then fi AC_SUBST(CFLAGS_ARMV8_CRC32C) -# In order to detect at runtime, if the ARM CRC Extension is available, -# we will do "getauxval(AT_HWCAP) & HWCAP_CRC32". Check if we have -# everything we need for that. -AC_CHECK_FUNCS([getauxval]) -AC_COMPILE_IFELSE([AC_LANG_PROGRAM([ -#include -#include -], [ -#ifndef AT_HWCAP -#error AT_HWCAP not defined -#endif -#ifndef HWCAP_CRC32 -#error HWCAP_CRC32 not defined -#endif -])], [HAVE_HWCAP_CRC32=1]) - # Select CRC-32C implementation. # # If we are targeting a processor that has Intel SSE 4.2 instructions, we can @@ -2060,9 +2044,8 @@ if test x"$USE_SLICING_BY_8_CRC32C" = x"" && test x"$USE_SSE42_CRC32C" = x"" && if test x"$pgac_armv8_crc32c_intrinsics" = x"yes" && test x"$CFLAGS_ARMV8_CRC32C" = x""; then USE_ARMV8_CRC32C=1 else - # ARM CRC Extension, with runtime check? The getauxval() function and - # HWCAP_CRC32 are needed for the runtime check. - if test x"$pgac_armv8_crc32c_intrinsics" = x"yes" && test x"$ac_cv_func_getauxval" = x"yes" && test x"$HAVE_HWCAP_CRC32" = x"1"; then + # ARM CRC Extension, with runtime check? + if test x"$pgac_armv8_crc32c_intrinsics" = x"yes"; then USE_ARMV8_CRC32C_WITH_RUNTIME_CHECK=1 else # fall back to slicing-by-8 algorithm, which doesn't require any diff --git a/src/port/pg_crc32c_armv8_choose.c b/src/port/pg_crc32c_armv8_choose.c index f21a8243e9a..de775dab3e5 100644 --- a/src/port/pg_crc32c_armv8_choose.c +++ b/src/port/pg_crc32c_armv8_choose.c @@ -8,10 +8,6 @@ * computation. Otherwise, fall back to the pure software implementation * (slicing-by-8). * - * XXX: The glibc-specific getauxval() function, with the HWCAP_CRC32 - * flag, is used to determine if the CRC Extension is available on the - * current platform. Is there a more portable way to determine that? - * * Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * @@ -24,17 +20,33 @@ #include "c.h" -#include -#include - +#include "libpq/pqsignal.h" #include "port/pg_crc32c.h" +#include + +static sigjmp_buf illegal_instruction_jump; + +static void +illegal_instruction_handler(int signo) +{ + siglongjmp(illegal_instruction_jump, 1); +} + static bool pg_crc32c_armv8_available(void) { - unsigned long auxv = getauxval(AT_HWCAP); + uint64 data = 42; + bool result; + + pqsignal(SIGILL, illegal_instruction_handler); + if (sigsetjmp(illegal_instruction_jump, 1) == 0) + result = (pg_comp_crc32c_armv8(0, &data, sizeof(data)) == 0xdd439b0d); + else + result = false; + pqsignal(SIGILL, SIG_DFL); - return (auxv & HWCAP_CRC32) != 0; + return result; } /* -- 2.17.0