From 55d007c8d6572b9e9f7b7037a28712ae81c76019 Mon Sep 17 00:00:00 2001
From: Thomas Munro <thomas.munro@enterprisedb.com>
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
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 | 34 ++++++++++++++++-------
 3 files changed, 29 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 <sys/auxv.h>
-#include <asm/hwcap.h>
-
-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 <sys/auxv.h>
-#include <asm/hwcap.h>
-], [
-#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..55896246548 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,37 @@
 
 #include "c.h"
 
-#include <sys/auxv.h>
-#include <asm/hwcap.h>
-
+#include "libpq/pqsignal.h"
 #include "port/pg_crc32c.h"
 
+#include <setjmp.h>
+
+pg_crc32c pg_crc32c_armv8_choose_dummy;
+
+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);
+	bool	result;
+
+	pqsignal(SIGILL, illegal_instruction_handler);
+	if (sigsetjmp(illegal_instruction_jump, 1) == 0)
+	{
+		pg_crc32c_armv8_choose_dummy = pg_comp_crc32c_armv8(0, 0, 0);
+		result = true;
+	}
+	else
+		result = false;
+	pqsignal(SIGILL, SIG_DFL);
 
-	return (auxv & HWCAP_CRC32) != 0;
+	return result;
 }
 
 /*
-- 
2.17.0

