From 4417458d62d1f75927b9f2e807e8843a49b01aa7 Mon Sep 17 00:00:00 2001
From: Erik Verbruggen <erik.verbruggen@theqtcompany.com>
Date: Fri, 11 Dec 2015 13:04:46 +0100
Subject: [PATCH] ARMv8: add crc32 feature detection.

Change-Id: I3cfac90dfa137d0bf3d124d87262eb2dbb56459c
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
---
 config.tests/arch/arch.cpp  |  3 +++
 src/corelib/tools/qsimd.cpp | 46 +++++++++++++++++++++++++++++++++----
 src/corelib/tools/qsimd_p.h | 24 +++++++++++++++++--
 3 files changed, 66 insertions(+), 7 deletions(-)

diff --git a/config.tests/arch/arch.cpp b/config.tests/arch/arch.cpp
index c4f23f7bcda..8e82d97d770 100644
--- a/config.tests/arch/arch.cpp
+++ b/config.tests/arch/arch.cpp
@@ -243,6 +243,9 @@ const char msg2[] = "==Qt=magic=Qt== Sub-architecture:"
 #ifdef __IWMMXT__
 " iwmmxt"
 #endif
+#ifdef __ARM_FEATURE_CRC32
+" crc32"
+#endif
 
 // -- SPARC --
 #ifdef __VIS__
diff --git a/src/corelib/tools/qsimd.cpp b/src/corelib/tools/qsimd.cpp
index 171e87df050..ef4ce741aa1 100644
--- a/src/corelib/tools/qsimd.cpp
+++ b/src/corelib/tools/qsimd.cpp
@@ -65,8 +65,15 @@
 #define HWCAP_VFPv3     8192
 #define HWCAP_VFPv3D16  16384
 
+// copied from <asm/hwcap.h> (ARM):
+#define HWCAP2_CRC32 (1 << 4)
+
+// copied from <asm/hwcap.h> (Aarch64)
+#define HWCAP_CRC32             (1 << 7)
+
 // copied from <linux/auxvec.h>
 #define AT_HWCAP  16    /* arch dependent hints at CPU capabilities */
+#define AT_HWCAP2 26    /* extension of AT_HWCAP */
 
 #elif defined(Q_CC_GHS)
 #include <INTEGRITY_types.h>
@@ -103,7 +110,16 @@ static inline quint64 detectProcessorFeatures()
 {
     quint64 features = 0;
 
-#if defined(Q_OS_LINUX)
+#if defined(Q_OS_IOS)
+    features |= Q_UINT64_C(1) << CpuFeatureNEON; // On iOS, NEON is always available.
+#  ifdef Q_PROCESSOR_ARM_V8
+    features |= Q_UINT64_C(1) << CpuFeatureCRC32; // On iOS, crc32 is always available if the architecture is Aarch32/64.
+#  endif
+    return features;
+#elif defined(Q_OS_LINUX)
+#  if defined(Q_PROCESSOR_ARM_V8) && defined(Q_PROCESSOR_ARM_64)
+    features |= Q_UINT64_C(1) << CpuFeatureNEON; // NEON is always available on ARMv8 64bit.
+#  endif
     int auxv = qt_safe_open("/proc/self/auxv", O_RDONLY);
     if (auxv != -1) {
         unsigned long vector[64];
@@ -116,12 +132,25 @@ static inline quint64 detectProcessorFeatures()
             }
 
             int max = nread / (sizeof vector[0]);
-            for (int i = 0; i < max; i += 2)
+            for (int i = 0; i < max; i += 2) {
                 if (vector[i] == AT_HWCAP) {
+#  if defined(Q_PROCESSOR_ARM_V8) && defined(Q_PROCESSOR_ARM_64)
+                    // For Aarch64:
+                    if (vector[i+1] & HWCAP_CRC32)
+                        features |= Q_UINT64_C(1) << CpuFeatureCRC32;
+#  endif
+                    // Aarch32, or ARMv7 or before:
                     if (vector[i+1] & HWCAP_NEON)
                         features |= Q_UINT64_C(1) << CpuFeatureNEON;
-                    break;
                 }
+#  if defined(Q_PROCESSOR_ARM_32)
+                // For Aarch32:
+                if (vector[i] == AT_HWCAP2) {
+                    if (vector[i+1] & HWCAP2_CRC32)
+                        features |= Q_UINT64_C(1) << CpuFeatureCRC32;
+                }
+#  endif
+            }
         }
 
         qt_safe_close(auxv);
@@ -133,6 +162,9 @@ static inline quint64 detectProcessorFeatures()
 #if defined(__ARM_NEON__)
     features = Q_UINT64_C(1) << CpuFeatureNEON;
 #endif
+#if defined(__ARM_FEATURE_CRC32)
+    features = Q_UINT64_C(1) << CpuFeatureCRC32;
+#endif
 
     return features;
 }
@@ -498,9 +530,13 @@ static inline uint detectProcessorFeatures()
 #if defined(Q_PROCESSOR_ARM)
 /* Data:
  neon
+ crc32
  */
-static const char features_string[] = " neon\0";
-static const int features_indices[] = { 0 };
+static const char features_string[] =
+        " neon\0"
+        " crc32\0"
+        "\0";
+static const int features_indices[] = { 0, 6 };
 #elif defined(Q_PROCESSOR_MIPS)
 /* Data:
  dsp
diff --git a/src/corelib/tools/qsimd_p.h b/src/corelib/tools/qsimd_p.h
index dedee06e386..7aa5099a32f 100644
--- a/src/corelib/tools/qsimd_p.h
+++ b/src/corelib/tools/qsimd_p.h
@@ -138,7 +138,18 @@
 
 #define QT_COMPILER_SUPPORTS(x)     (QT_COMPILER_SUPPORTS_ ## x - 0)
 
-#if (defined(Q_CC_INTEL) || defined(Q_CC_MSVC) \
+#if defined(Q_PROCESSOR_ARM)
+#  define QT_COMPILER_SUPPORTS_HERE(x)    (__ARM_FEATURE_ ## x)
+#  if defined(Q_CC_GNU) && !defined(Q_CC_INTEL) && Q_CC_GNU >= 600
+     /* GCC requires attributes for a function */
+#    define QT_FUNCTION_TARGET(x)  __attribute__((__target__(QT_FUNCTION_TARGET_STRING_ ## x)))
+#  else
+#    define QT_FUNCTION_TARGET(x)
+#  endif
+#  if !defined(__ARM_FEATURE_NEON) && defined(__ARM_NEON__)
+#    define __ARM_FEATURE_NEON           // also support QT_COMPILER_SUPPORTS_HERE(NEON)
+#  endif
+#elif (defined(Q_CC_INTEL) || defined(Q_CC_MSVC) \
     || (defined(Q_CC_GNU) && !defined(Q_CC_CLANG) && (__GNUC__-0) * 100 + (__GNUC_MINOR__-0) >= 409)) \
     && !defined(QT_BOOTSTRAPPED)
 #  define QT_COMPILER_SUPPORTS_SIMD_ALWAYS
@@ -253,12 +264,17 @@
 // note: as of GCC 4.9, does not support function targets for ARM
 #if defined(__ARM_NEON) || defined(__ARM_NEON__)
 #include <arm_neon.h>
-#define QT_FUNCTION_TARGET_STRING_ARM_NEON      "neon"
+#define QT_FUNCTION_TARGET_STRING_NEON      "+neon" // unused: gcc doesn't support function targets on non-aarch64, and on Aarch64 NEON is always available.
 #ifndef __ARM_NEON__
 // __ARM_NEON__ is not defined on AArch64, but we need it in our NEON detection.
 #define __ARM_NEON__
 #endif
 #endif
+// AArch64/ARM64
+#if defined(Q_PROCESSOR_ARM_V8)
+#define QT_FUNCTION_TARGET_STRING_CRC32      "+crc"
+#  include <arm_acle.h>
+#endif
 
 #undef QT_COMPILER_SUPPORTS_SIMD_ALWAYS
 
@@ -269,6 +285,7 @@ enum CPUFeatures {
 #if defined(Q_PROCESSOR_ARM)
     CpuFeatureNEON          = 0,
     CpuFeatureARM_NEON      = CpuFeatureNEON,
+    CpuFeatureCRC32         = 1,
 #elif defined(Q_PROCESSOR_MIPS)
     CpuFeatureDSP           = 0,
     CpuFeatureDSPR2         = 1,
@@ -396,6 +413,9 @@ static const quint64 qCompilerCpuFeatures = 0
 #if defined __ARM_NEON__
         | (Q_UINT64_C(1) << CpuFeatureNEON)
 #endif
+#if defined __ARM_FEATURE_CRC32
+        | (Q_UINT64_C(1) << CpuFeatureCRC32)
+#endif
 #if defined __mips_dsp
         | (Q_UINT64_C(1) << CpuFeatureDSP)
 #endif
-- 
GitLab