commit f4af49dc0b04c8ea4608428c79d3f5629c5d7267
Author: Allan Sandfeld Jensen <allan.jensen@qt.io>
Date:   Thu Mar 2 17:20:07 2017 +0100

    WIP: AES hash
    
    Change-Id: Ia5b511c059d63321d2f88f661f449085bff87ded

diff --git a/config.tests/common/aes/aes.cpp b/config.tests/common/aes/aes.cpp
new file mode 100644
index 0000000..ba7402d
--- /dev/null
+++ b/config.tests/common/aes/aes.cpp
@@ -0,0 +1,50 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the config.tests of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <wmmintrin.h>
+
+int main(int, char**)
+{
+    __m128i data;
+    __m128i key0, key1;
+    data = _mm_aesenc_si128(data, key0);
+    data = _mm_aesenclast_si128(data, key1);
+    (void)data;
+    return 0;
+}
diff --git a/config.tests/common/aes/aes.pro b/config.tests/common/aes/aes.pro
new file mode 100644
index 0000000..554d34e
--- /dev/null
+++ b/config.tests/common/aes/aes.pro
@@ -0,0 +1,4 @@
+SOURCES = aes.cpp
+CONFIG -= qt dylib release debug_and_release
+CONFIG += debug console
+QMAKE_CXXFLAGS += $$QMAKE_CFLAGS_AES
diff --git a/configure.json b/configure.json
index c5be888..685f640 100644
--- a/configure.json
+++ b/configure.json
@@ -384,6 +384,11 @@
             "test": "common/avx512",
             "args": "AVX512=VBMI"
         },
+        "aes": {
+            "label": "AES instructions",
+            "type": "compile",
+            "test": "common/aes"
+        },
         "mips_dsp": {
             "label": "MIPS DSP instructions",
             "type": "subarch",
@@ -869,6 +874,14 @@
                 { "type": "define", "name": "QT_COMPILER_SUPPORTS_AVX512VBMI", "value": 1 }
             ]
         },
+        "aes": {
+            "label": "AES",
+            "condition": "features.sse4_2 && tests.aes",
+            "output": [
+                "privateConfig",
+                { "type": "define", "name": "QT_COMPILER_SUPPORTS_AES", "value": 1 }
+            ]
+        },
         "mips_dsp": {
             "label": "DSP",
             "condition": "arch.mips && tests.mips_dsp",
@@ -1120,7 +1133,7 @@ Configure with '-qreal float' to create a build that is binary-compatible with 5
                         {
                             "message": "SSE",
                             "type": "featureList",
-                            "args": "sse2 sse3 ssse3 sse4_1 sse4_2",
+                            "args": "sse2 sse3 ssse3 sse4_1 sse4_2 aes",
                             "condition": "(arch.i386 || arch.x86_64)"
                         },
                         {
diff --git a/mkspecs/common/gcc-base.conf b/mkspecs/common/gcc-base.conf
index 9ddebae..b955471 100644
--- a/mkspecs/common/gcc-base.conf
+++ b/mkspecs/common/gcc-base.conf
@@ -86,6 +86,7 @@ QMAKE_CFLAGS_SSSE3     += -mssse3
 QMAKE_CFLAGS_SSE4_1    += -msse4.1
 QMAKE_CFLAGS_SSE4_2    += -msse4.2
 QMAKE_CFLAGS_F16C      += -mf16c
+QMAKE_CFLAGS_AES       += -maes
 QMAKE_CFLAGS_AVX       += -mavx
 QMAKE_CFLAGS_AVX2      += -mavx2
 QMAKE_CFLAGS_AVX512F   += -mavx512f
diff --git a/src/corelib/tools/qhash.cpp b/src/corelib/tools/qhash.cpp
index 9270539..2d62b75 100644
--- a/src/corelib/tools/qhash.cpp
+++ b/src/corelib/tools/qhash.cpp
@@ -74,25 +74,6 @@
 
 QT_BEGIN_NAMESPACE
 
-/*
-    The Java's hashing algorithm for strings is a variation of D. J. Bernstein
-    hashing algorithm appeared here http://cr.yp.to/cdb/cdb.txt
-    and informally known as DJB33XX - DJB's 33 Times Xor.
-    Java uses DJB31XA, that is, 31 Times Add.
-
-    The original algorithm was a loop around
-        (h << 5) + h ^ c
-    (which is indeed h*33 ^ c); it was then changed to
-        (h << 5) - h ^ c
-    (so h*31^c: DJB31XX), and the XOR changed to a sum:
-        (h << 5) - h + c
-    (DJB31XA), which can save some assembly instructions.
-
-    Still, we can avoid writing the multiplication as "(h << 5) - h"
-    -- the compiler will turn it into a shift and an addition anyway
-    (for instance, gcc 4.4 does that even at -O0).
-*/
-
 #if QT_COMPILER_SUPPORTS_HERE(SSE4_2)
 static inline bool hasFastCrc32()
 {
@@ -137,6 +118,7 @@ static uint crc32(const Char *ptr, size_t len, uint h)
         h = _mm_crc32_u8(h, *p);
     return h;
 }
+
 #elif defined(__ARM_FEATURE_CRC32)
 static inline bool hasFastCrc32()
 {
@@ -199,10 +181,127 @@ static uint crc32(...)
 }
 #endif
 
+#if QT_COMPILER_SUPPORTS_HERE(AES)
+static inline bool hasFastAES()
+{
+    return qCpuHasFeature(AES);
+}
+
+template <typename Char>
+QT_FUNCTION_TARGET(AES)
+static uint aeshash(const Char *ptr, size_t len, uint h)
+{
+    // We calculate an AES hash by using the hash seed as the data
+    // to encrypt and the hash input as the AES round keys.
+    // Note that despite the AES basis, this is NOT a cryptographic hash,
+    // but nor does it need to be for our purpose here.
+    // It can be made stronger by generating better round keys from the
+    // hash input, but we should probably have 64-bit hash seeds first.
+    const uchar *p = reinterpret_cast<const uchar *>(ptr);
+    const uchar *const e = p + (len * sizeof(Char));
+    __m128i vh = _mm_cvtsi32_si128(h);
+    vh = _mm_aesenc_si128(vh, _mm_setzero_si128());
+    p += 16;
+    for ( ; p <= e; p += 16) {
+        __m128i rndkey = _mm_loadu_si128((const __m128i *)(p - 16));
+        rndKey = _mm_aesenclast_si128(rndKey, _mm_setzero_si128());
+        vh = _mm_aesenc_si128(vh, rndkey);
+    }
+    p -= 16;
+
+    p += 8;
+    if (p <= e) {
+        __m128i rndkey = _mm_loadl_epi64((const __m128i *)(p - 8));
+        rndKey = _mm_aesenclast_si128(rndKey, _mm_setzero_si128());
+        vh = _mm_aesenc_si128(vh, rndkey);
+        p += 8;
+    }
+    p -= 8;
+
+    p += 4;
+    if (p <= e) {
+        __m128i rndkey = _mm_cvtsi32_si128(qFromUnaligned<uint32_t>(p - 4));
+        rndKey = _mm_aesenclast_si128(rndKey, _mm_setzero_si128());
+        vh = _mm_aesenc_si128(vh, rndkey);
+        p += 4;
+    }
+    p -= 4;
+
+    uint64_t lastkey = 0;
+    if (p < e)
+        memcpy(&lastkey, p, e - p);
+    lastkey |= (len << 32);
+    __m128i rndkey = _mm_loadl_epi64((const __m128i *)&lastkey);
+    rndKey = _mm_aesenclast_si128(rndKey, _mm_setzero_si128());
+    vh = _mm_aesenc_si128(vh, rndKey);
+    vh = _mm_aesenclast_si128(vh, _mm_setzero_si128());
+    return _mm_cvtsi128_si32(vh);
+}
+#elif defined(__ARM_FEATURE_CRYPTO)
+static inline bool hasFastAES()
+{
+    return qCpuHasFeature(CRYPTO);
+}
+
+template <typename Char>
+static uint aeshash(const Char *ptr, size_t len, uint h)
+{
+    const uchar *p = reinterpret_cast<const uchar *>(ptr);
+    const uchar *const e = p + (len * sizeof(Char));
+    uint8x16_t vh = vreinterpretq_u8_u32(vmovq_u32(h));
+    vh = vaeseq_u8(vh, vmovq_n_u8(0));
+    vh = vaesmcq_u8(vh);
+    p += 16;
+    for ( ; p <= e; p += 16) {
+        uint8x16_t rndkey = vld1q_u8(p - 16);
+        rndKey = vaeseq_u8(rndKey, vmovq_n_u8(0));
+        vh = vaeseq_u8(vh, rndkey);
+        vh = vaesmcq_u8(vh);
+    }
+    p -= 16;
+
+    p += 8;
+    if (p <= e) {
+        uint8x16_t rndkey = vcombine_u8(vld1_u8(p - 8), vmov_n_u8(0));
+        rndKey = vaeseq_u8(rndKey, vmovq_n_u8(0));
+        vh = vaeseq_u8(vh, rndkey);
+        vh = vaesmcq_u8(vh);
+        p += 8;
+    }
+    p -= 8;
+
+    uint64_t lastkey = 0;
+    if (p < e)
+        memcpy(&lastkey, p, e - p);
+    lastkey ^= (len << 32);
+    uint8x16_t rndkey = vreinterpretq_u8_u64(vmovq_n_u64(lastkey));
+    rndKey = vaeseq_u8(rndKey, vmovq_n_u8(0));
+    vh = vaeseq_u8(vh, rndkey);
+    vh = vaesmcq_u8(vh);
+    vh = vaeseq_u8(vh, vmovq_n_u8(0));
+    return _mm_cvtsi128_si32(vh);
+
+}
+#else
+static inline bool hasFastAES()
+{
+    return false;
+}
+
+static uint aeshash(...)
+{
+    Q_UNREACHABLE();
+    return 0;
+}
+#endif
+
 static inline uint hash(const uchar *p, size_t len, uint seed) Q_DECL_NOTHROW
 {
     uint h = seed;
 
+    if (hasFastAES())
+        return aeshash(p, len, h);
+
     if (hasFastCrc32())
         return crc32(p, len, h);
 
@@ -221,6 +320,9 @@ static inline uint hash(const QChar *p, size_t len, uint seed) Q_DECL_NOTHROW
 {
     uint h = seed;
 
+    if (hasFastAES())
+        return aeshash(p, len, h);
+
     if (hasFastCrc32())
         return crc32(p, len, h);
 
diff --git a/src/corelib/tools/qsimd_p.h b/src/corelib/tools/qsimd_p.h
index f6164e2..6b63575 100644
--- a/src/corelib/tools/qsimd_p.h
+++ b/src/corelib/tools/qsimd_p.h
@@ -339,6 +339,7 @@ enum CPUFeatures {
     CpuFeatureNEON          = 0,
     CpuFeatureARM_NEON      = CpuFeatureNEON,
     CpuFeatureCRC32         = 1,
+    CpuFeatureCRYPTO        = 2,
 #elif defined(Q_PROCESSOR_MIPS)
     CpuFeatureDSP           = 0,
     CpuFeatureDSPR2         = 1,
@@ -469,6 +470,9 @@ static const quint64 qCompilerCpuFeatures = 0
 #if defined __ARM_FEATURE_CRC32
         | (Q_UINT64_C(1) << CpuFeatureCRC32)
 #endif
+#if defined __ARM_FEATURE_CRYPTO
+        | (Q_UINT64_C(1) << CpuFeatureCRYPTO)
+#endif
 #if defined __mips_dsp
         | (Q_UINT64_C(1) << CpuFeatureDSP)
 #endif
