aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/core/SkOpts.cpp9
-rw-r--r--src/opts/SkChecksum_opts.h48
-rw-r--r--src/opts/SkOpts_crc32.cpp17
3 files changed, 71 insertions, 3 deletions
diff --git a/src/core/SkOpts.cpp b/src/core/SkOpts.cpp
index a4da111630..95781a3977 100644
--- a/src/core/SkOpts.cpp
+++ b/src/core/SkOpts.cpp
@@ -81,15 +81,22 @@ namespace SkOpts {
void Init_sse42();
void Init_avx();
void Init_avx2() {}
+ void Init_crc32();
static void init() {
- #if defined(SK_CPU_X86) && !defined(SK_BUILD_NO_OPTS)
+#if !defined(SK_BUILD_NO_OPTS)
+ #if defined(SK_CPU_X86)
if (SkCpu::Supports(SkCpu::SSSE3)) { Init_ssse3(); }
if (SkCpu::Supports(SkCpu::SSE41)) { Init_sse41(); }
if (SkCpu::Supports(SkCpu::SSE42)) { Init_sse42(); }
if (SkCpu::Supports(SkCpu::AVX )) { Init_avx(); }
if (SkCpu::Supports(SkCpu::AVX2 )) { Init_avx2(); }
+
+ #elif defined(SK_CPU_ARM64)
+ if (SkCpu::Supports(SkCpu::CRC32)) { Init_crc32(); }
+
#endif
+#endif
}
void Init() {
diff --git a/src/opts/SkChecksum_opts.h b/src/opts/SkChecksum_opts.h
index 07fdfaab65..4bcd9b1c35 100644
--- a/src/opts/SkChecksum_opts.h
+++ b/src/opts/SkChecksum_opts.h
@@ -13,10 +13,10 @@
#if SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE42
#include <immintrin.h>
+#elif defined(SK_CPU_ARM64) && defined(__ARM_FEATURE_CRC32)
+ #include <arm_acle.h>
#endif
-// TODO: ARMv8 has optional CRC instructions similar to SSE 4.2
-
namespace SK_OPTS_NS {
template <typename T>
@@ -127,6 +127,50 @@ static inline T unaligned_load(const uint8_t* src) {
return hash;
}
+#elif defined(SK_CPU_ARM64) && defined(__ARM_FEATURE_CRC32)
+ static uint32_t hash_fn(const void* vdata, size_t bytes, uint32_t hash) {
+ auto data = (const uint8_t*)vdata;
+ if (bytes >= 24) {
+ uint32_t a = hash,
+ b = hash,
+ c = hash;
+ size_t steps = bytes/24;
+ while (steps --> 0) {
+ a = __crc32d(a, unaligned_load<uint64_t>(data+ 0));
+ b = __crc32d(b, unaligned_load<uint64_t>(data+ 8));
+ c = __crc32d(c, unaligned_load<uint64_t>(data+16));
+ data += 24;
+ }
+ bytes %= 24;
+ hash = a^b^c;
+ }
+
+ SkASSERT(bytes < 24);
+ if (bytes >= 16) {
+ hash = __crc32d(hash, unaligned_load<uint64_t>(data));
+ bytes -= 8;
+ data += 8;
+ }
+
+ SkASSERT(bytes < 16);
+ if (bytes & 8) {
+ hash = __crc32d(hash, unaligned_load<uint64_t>(data));
+ data += 8;
+ }
+ if (bytes & 4) {
+ hash = __crc32w(hash, unaligned_load<uint32_t>(data));
+ data += 4;
+ }
+ if (bytes & 2) {
+ hash = __crc32h(hash, unaligned_load<uint16_t>(data));
+ data += 2;
+ }
+ if (bytes & 1) {
+ hash = __crc32b(hash, unaligned_load<uint8_t>(data));
+ }
+ return hash;
+ }
+
#else
// This is Murmur3.
static uint32_t hash_fn(const void* vdata, size_t bytes, uint32_t hash) {
diff --git a/src/opts/SkOpts_crc32.cpp b/src/opts/SkOpts_crc32.cpp
new file mode 100644
index 0000000000..8fc88aa7f5
--- /dev/null
+++ b/src/opts/SkOpts_crc32.cpp
@@ -0,0 +1,17 @@
+/*
+ * Copyright 2016 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkOpts.h"
+
+#define SK_OPTS_NS crc32
+#include "SkChecksum_opts.h"
+
+namespace SkOpts {
+ void Init_crc32() {
+ hash_fn = crc32::hash_fn;
+ }
+}