1 | /******************************************************************** |
2 | * Copyright (c) 2013 - 2014, Pivotal Inc. |
3 | * All rights reserved. |
4 | * |
5 | * Author: Zhanwei Wang |
6 | ********************************************************************/ |
7 | /******************************************************************** |
8 | * 2014 - |
9 | * open source under Apache License Version 2.0 |
10 | ********************************************************************/ |
11 | /** |
12 | * Licensed to the Apache Software Foundation (ASF) under one |
13 | * or more contributor license agreements. See the NOTICE file |
14 | * distributed with this work for additional information |
15 | * regarding copyright ownership. The ASF licenses this file |
16 | * to you under the Apache License, Version 2.0 (the |
17 | * "License"); you may not use this file except in compliance |
18 | * with the License. You may obtain a copy of the License at |
19 | * |
20 | * http://www.apache.org/licenses/LICENSE-2.0 |
21 | * |
22 | * Unless required by applicable law or agreed to in writing, software |
23 | * distributed under the License is distributed on an "AS IS" BASIS, |
24 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
25 | * See the License for the specific language governing permissions and |
26 | * limitations under the License. |
27 | */ |
28 | #include <cassert> |
29 | #include <cstdlib> |
30 | |
31 | #include "HWCrc32c.h" |
32 | |
33 | #if ((defined(__X86__) || defined(__i386__) || defined(i386) || defined(_M_IX86) || defined(__386__) || defined(__x86_64__) || defined(_M_X64))) |
34 | #include <cpuid.h> |
35 | #endif |
36 | |
37 | #if ((defined(__X86__) || defined(__i386__) || defined(i386) || defined(_M_IX86) || defined(__386__) || defined(__x86_64__) || defined(_M_X64))) |
38 | #if !defined(__SSE4_2__) |
39 | |
40 | namespace Hdfs { |
41 | namespace Internal { |
42 | |
43 | #if defined(__LP64__) |
44 | static inline uint64_t _mm_crc32_u64(uint64_t crc, uint64_t value) { |
45 | asm("crc32q %[value], %[crc]\n" : [crc] "+r" (crc) : [value] "rm" (value)); |
46 | return crc; |
47 | } |
48 | #endif |
49 | |
50 | static inline uint32_t _mm_crc32_u16(uint32_t crc, uint16_t value) { |
51 | asm("crc32w %[value], %[crc]\n" : [crc] "+r" (crc) : [value] "rm" (value)); |
52 | return crc; |
53 | } |
54 | |
55 | static inline uint32_t _mm_crc32_u32(uint32_t crc, uint64_t value) { |
56 | asm("crc32l %[value], %[crc]\n" : [crc] "+r" (crc) : [value] "rm" (value)); |
57 | return crc; |
58 | } |
59 | |
60 | static inline uint32_t _mm_crc32_u8(uint32_t crc, uint8_t value) { |
61 | asm("crc32b %[value], %[crc]\n" : [crc] "+r" (crc) : [value] "rm" (value)); |
62 | return crc; |
63 | } |
64 | |
65 | } |
66 | } |
67 | |
68 | #else |
69 | |
70 | #include <nmmintrin.h> |
71 | |
72 | #endif |
73 | |
74 | namespace Hdfs { |
75 | namespace Internal { |
76 | |
77 | bool HWCrc32c::available() { |
78 | #if ((defined(__X86__) || defined(__i386__) || defined(i386) || defined(_M_IX86) || defined(__386__) || defined(__x86_64__) || defined(_M_X64))) |
79 | uint32_t eax, ebx, ecx = 0, edx; |
80 | /* |
81 | * get the CPU features (level 1). ecx will have the SSE4.2 bit. |
82 | * This gcc routine automatically handles saving ebx in the case where we are -fpic or -fPIC |
83 | */ |
84 | __get_cpuid(1, &eax, &ebx, &ecx, &edx); |
85 | return (ecx & (1 << 20)) != 0; |
86 | #else |
87 | return false; |
88 | #endif |
89 | } |
90 | |
91 | void HWCrc32c::update(const void * b, int len) { |
92 | const char * p = static_cast<const char *>(b); |
93 | #if defined(__LP64__) |
94 | const size_t bytes = sizeof(uint64_t); |
95 | #else |
96 | const size_t bytes = sizeof(uint32_t); |
97 | #endif |
98 | int align = bytes - reinterpret_cast<uint64_t>(p) % bytes; |
99 | align = bytes == static_cast<size_t>(align) ? 0 : align; |
100 | |
101 | if (len < align) { |
102 | align = len; |
103 | } |
104 | |
105 | updateInt64(p, align); |
106 | p = p + align; |
107 | len -= align; |
108 | |
109 | if (len > 0) { |
110 | assert(0 == reinterpret_cast<uint64_t>(p) % bytes); |
111 | |
112 | for (int i = len / bytes; i > 0; --i) { |
113 | #if defined(__LP64__) |
114 | crc = _mm_crc32_u64(crc, *reinterpret_cast<const uint64_t *>(p)); |
115 | #else |
116 | crc = _mm_crc32_u32(crc, *reinterpret_cast<const uint32_t *>(p)); |
117 | #endif |
118 | p = p + bytes; |
119 | } |
120 | |
121 | len &= bytes - 1; |
122 | updateInt64(p, len); |
123 | } |
124 | } |
125 | |
126 | void HWCrc32c::updateInt64(const char * b, int len) { |
127 | assert(len < 8); |
128 | |
129 | switch (len) { |
130 | case 7: |
131 | crc = _mm_crc32_u8(crc, *reinterpret_cast<const uint8_t *>(b++)); |
132 | |
133 | case 6: |
134 | crc = _mm_crc32_u16(crc, *reinterpret_cast<const uint16_t *>(b)); |
135 | b += 2; |
136 | |
137 | /* case 5 is below: 4 + 1 */ |
138 | case 4: |
139 | crc = _mm_crc32_u32(crc, *reinterpret_cast<const uint32_t *>(b)); |
140 | break; |
141 | |
142 | case 3: |
143 | crc = _mm_crc32_u8(crc, *reinterpret_cast<const uint8_t *>(b++)); |
144 | |
145 | case 2: |
146 | crc = _mm_crc32_u16(crc, *reinterpret_cast<const uint16_t *>(b)); |
147 | break; |
148 | |
149 | case 5: |
150 | crc = _mm_crc32_u32(crc, *reinterpret_cast<const uint32_t *>(b)); |
151 | b += 4; |
152 | |
153 | case 1: |
154 | crc = _mm_crc32_u8(crc, *reinterpret_cast<const uint8_t *>(b)); |
155 | break; |
156 | |
157 | case 0: |
158 | break; |
159 | } |
160 | } |
161 | |
162 | } |
163 | } |
164 | |
165 | #endif /* _HDFS_LIBHDFS3_COMMON_HWCHECKSUM_H_ */ |
166 | |