1 // Copyright 2016 The LevelDB Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. See the AUTHORS file for names of contributors.
5 // A portable implementation of crc32c, optimized to handle
6 // four bytes at a time.
8 // In a separate source file to allow this accelerated CRC32C function to be
9 // compiled with the appropriate compiler flags to enable x86 SSE 4.2
14 #include "port/port.h"
16 #if defined(LEVELDB_PLATFORM_POSIX_SSE)
20 #elif defined(__GNUC__) && defined(__SSE4_2__)
21 #include <nmmintrin.h>
24 #endif // defined(LEVELDB_PLATFORM_POSIX_SSE)
29 #if defined(LEVELDB_PLATFORM_POSIX_SSE)
31 // Used to fetch a naturally-aligned 32-bit word in little endian byte-order
32 static inline uint32_t LE_LOAD32(const uint8_t *p
) {
33 // SSE is x86 only, so ensured that |p| is always little-endian.
35 memcpy(&word
, p
, sizeof(word
));
39 #if defined(_M_X64) || defined(__x86_64__) // LE_LOAD64 is only used on x64.
41 // Used to fetch a naturally-aligned 64-bit word in little endian byte-order
42 static inline uint64_t LE_LOAD64(const uint8_t *p
) {
44 memcpy(&dword
, p
, sizeof(dword
));
48 #endif // defined(_M_X64) || defined(__x86_64__)
50 #endif // defined(LEVELDB_PLATFORM_POSIX_SSE)
52 // For further improvements see Intel publication at:
53 // http://download.intel.com/design/intarch/papers/323405.pdf
54 uint32_t AcceleratedCRC32C(uint32_t crc
, const char* buf
, size_t size
) {
55 #if !defined(LEVELDB_PLATFORM_POSIX_SSE)
59 const uint8_t *p
= reinterpret_cast<const uint8_t *>(buf
);
60 const uint8_t *e
= p
+ size
;
61 uint32_t l
= crc
^ 0xffffffffu
;
64 l = _mm_crc32_u8(l, *p++); \
67 l = _mm_crc32_u32(l, LE_LOAD32(p)); \
71 l = _mm_crc32_u64(l, LE_LOAD64(p)); \
76 // Process unaligned bytes
77 for (unsigned int i
= reinterpret_cast<uintptr_t>(p
) % 8; i
; --i
) {
81 // _mm_crc32_u64 is only available on x64.
82 #if defined(_M_X64) || defined(__x86_64__)
83 // Process 8 bytes at a time
87 // Process 4 bytes at a time
91 #else // !(defined(_M_X64) || defined(__x86_64__))
92 // Process 4 bytes at a time
96 #endif // defined(_M_X64) || defined(__x86_64__)
98 // Process the last few bytes
105 return l
^ 0xffffffffu
;
106 #endif // defined(LEVELDB_PLATFORM_POSIX_SSE)
110 } // namespace leveldb