summaryrefslogtreecommitdiffstats
path: root/src/corelib/tools/qhash.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/corelib/tools/qhash.cpp')
-rw-r--r--src/corelib/tools/qhash.cpp63
1 files changed, 63 insertions, 0 deletions
diff --git a/src/corelib/tools/qhash.cpp b/src/corelib/tools/qhash.cpp
index f14fac00b8..18d1cee0eb 100644
--- a/src/corelib/tools/qhash.cpp
+++ b/src/corelib/tools/qhash.cpp
@@ -60,6 +60,7 @@
#include <qbytearray.h>
#include <qdatetime.h>
#include <qbasicatomic.h>
+#include <private/qsimd_p.h>
#ifndef QT_BOOTSTRAPPED
#include <qcoreapplication.h>
@@ -93,10 +94,69 @@ QT_BEGIN_NAMESPACE
(for instance, gcc 4.4 does that even at -O0).
*/
+#ifdef __SSE4_2__
+static inline bool hasFastCrc32()
+{
+ return true;
+}
+
+template <typename Char>
+static uint crc32(const Char *ptr, size_t len, uint h)
+{
+ // The CRC32 instructions from Nehalem calculate a 32-bit CRC32 checksum
+ const uchar *p = reinterpret_cast<const uchar *>(ptr);
+ const uchar *const e = p + (len * sizeof(Char));
+# ifdef Q_PROCESSOR_X86_64
+ // The 64-bit instruction still calculates only 32-bit, but without this
+ // variable GCC 4.9 still tries to clear the high bits on every loop
+ qulonglong h2 = h;
+
+ p += 8;
+ for ( ; p <= e; p += 8)
+ h2 = _mm_crc32_u64(h2, *reinterpret_cast<const qlonglong *>(p - 8));
+ h = h2;
+ p -= 8;
+
+ len = e - p;
+ if (len & 4) {
+ h = _mm_crc32_u32(h, *reinterpret_cast<const uint *>(p));
+ p += 4;
+ }
+# else
+ p += 4;
+ for ( ; p <= e; p += 4)
+ h = _mm_crc32_u32(h, *reinterpret_cast<const uint *>(p));
+ p -= 4;
+ len = e - p;
+# endif
+ if (len & 2) {
+ h = _mm_crc32_u16(h, *reinterpret_cast<const ushort *>(p));
+ p += 2;
+ }
+ if (sizeof(Char) == 1 && len & 1)
+ h = _mm_crc32_u8(h, *p);
+ return h;
+}
+#else
+static inline bool hasFastCrc32()
+{
+ return false;
+}
+
+static uint crc32(...)
+{
+ Q_UNREACHABLE();
+ return 0;
+}
+#endif
+
static inline uint hash(const uchar *p, int len, uint seed) Q_DECL_NOTHROW
{
uint h = seed;
+ if (hasFastCrc32())
+ return crc32(p, size_t(len), h);
+
for (int i = 0; i < len; ++i)
h = 31 * h + p[i];
@@ -107,6 +167,9 @@ static inline uint hash(const QChar *p, int len, uint seed) Q_DECL_NOTHROW
{
uint h = seed;
+ if (hasFastCrc32())
+ return crc32(p, size_t(len), h);
+
for (int i = 0; i < len; ++i)
h = 31 * h + p[i].unicode();