hash: split x86 and SW hash CRC intrinsics
[dpdk.git] / lib / hash / rte_hash_crc.h
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2010-2014 Intel Corporation
3  */
4
5 #ifndef _RTE_HASH_CRC_H_
6 #define _RTE_HASH_CRC_H_
7
8 /**
9  * @file
10  *
11  * RTE CRC Hash
12  */
13
14 #ifdef __cplusplus
15 extern "C" {
16 #endif
17
18 #include <stdint.h>
19 #include <rte_config.h>
20 #include <rte_cpuflags.h>
21 #include <rte_branch_prediction.h>
22 #include <rte_common.h>
23
24 #include "rte_crc_sw.h"
25
26 #define CRC32_SW            (1U << 0)
27 #define CRC32_SSE42         (1U << 1)
28 #define CRC32_x64           (1U << 2)
29 #define CRC32_SSE42_x64     (CRC32_x64|CRC32_SSE42)
30 #define CRC32_ARM64         (1U << 3)
31
32 static uint8_t crc32_alg = CRC32_SW;
33
34 #if defined(RTE_ARCH_ARM64) && defined(__ARM_FEATURE_CRC32)
35 #include "rte_crc_arm64.h"
36 #else
37 #include "rte_crc_x86.h"
38
39 /**
40  * Allow or disallow use of SSE4.2 instrinsics for CRC32 hash
41  * calculation.
42  *
43  * @param alg
44  *   An OR of following flags:
45  *   - (CRC32_SW) Don't use SSE4.2 intrinsics
46  *   - (CRC32_SSE42) Use SSE4.2 intrinsics if available
47  *   - (CRC32_SSE42_x64) Use 64-bit SSE4.2 intrinsic if available (default)
48  *
49  */
50 static inline void
51 rte_hash_crc_set_alg(uint8_t alg)
52 {
53 #if defined(RTE_ARCH_X86)
54         if (alg == CRC32_SSE42_x64 &&
55                         !rte_cpu_get_flag_enabled(RTE_CPUFLAG_EM64T))
56                 alg = CRC32_SSE42;
57 #endif
58         crc32_alg = alg;
59 }
60
61 /* Setting the best available algorithm */
62 RTE_INIT(rte_hash_crc_init_alg)
63 {
64         rte_hash_crc_set_alg(CRC32_SSE42_x64);
65 }
66
67 /**
68  * Use single crc32 instruction to perform a hash on a byte value.
69  * Fall back to software crc32 implementation in case SSE4.2 is
70  * not supported
71  *
72  * @param data
73  *   Data to perform hash on.
74  * @param init_val
75  *   Value to initialise hash generator.
76  * @return
77  *   32bit calculated hash value.
78  */
79 static inline uint32_t
80 rte_hash_crc_1byte(uint8_t data, uint32_t init_val)
81 {
82 #if defined RTE_ARCH_X86
83         if (likely(crc32_alg & CRC32_SSE42))
84                 return crc32c_sse42_u8(data, init_val);
85 #endif
86
87         return crc32c_1byte(data, init_val);
88 }
89
90 /**
91  * Use single crc32 instruction to perform a hash on a 2 bytes value.
92  * Fall back to software crc32 implementation in case SSE4.2 is
93  * not supported
94  *
95  * @param data
96  *   Data to perform hash on.
97  * @param init_val
98  *   Value to initialise hash generator.
99  * @return
100  *   32bit calculated hash value.
101  */
102 static inline uint32_t
103 rte_hash_crc_2byte(uint16_t data, uint32_t init_val)
104 {
105 #if defined RTE_ARCH_X86
106         if (likely(crc32_alg & CRC32_SSE42))
107                 return crc32c_sse42_u16(data, init_val);
108 #endif
109
110         return crc32c_2bytes(data, init_val);
111 }
112
113 /**
114  * Use single crc32 instruction to perform a hash on a 4 byte value.
115  * Fall back to software crc32 implementation in case SSE4.2 is
116  * not supported
117  *
118  * @param data
119  *   Data to perform hash on.
120  * @param init_val
121  *   Value to initialise hash generator.
122  * @return
123  *   32bit calculated hash value.
124  */
125 static inline uint32_t
126 rte_hash_crc_4byte(uint32_t data, uint32_t init_val)
127 {
128 #if defined RTE_ARCH_X86
129         if (likely(crc32_alg & CRC32_SSE42))
130                 return crc32c_sse42_u32(data, init_val);
131 #endif
132
133         return crc32c_1word(data, init_val);
134 }
135
136 /**
137  * Use single crc32 instruction to perform a hash on a 8 byte value.
138  * Fall back to software crc32 implementation in case SSE4.2 is
139  * not supported
140  *
141  * @param data
142  *   Data to perform hash on.
143  * @param init_val
144  *   Value to initialise hash generator.
145  * @return
146  *   32bit calculated hash value.
147  */
148 static inline uint32_t
149 rte_hash_crc_8byte(uint64_t data, uint32_t init_val)
150 {
151 #ifdef RTE_ARCH_X86_64
152         if (likely(crc32_alg == CRC32_SSE42_x64))
153                 return crc32c_sse42_u64(data, init_val);
154 #endif
155
156 #if defined RTE_ARCH_X86
157         if (likely(crc32_alg & CRC32_SSE42))
158                 return crc32c_sse42_u64_mimic(data, init_val);
159 #endif
160
161         return crc32c_2words(data, init_val);
162 }
163
164 #endif
165
166 /**
167  * Calculate CRC32 hash on user-supplied byte array.
168  *
169  * @param data
170  *   Data to perform hash on.
171  * @param data_len
172  *   How many bytes to use to calculate hash value.
173  * @param init_val
174  *   Value to initialise hash generator.
175  * @return
176  *   32bit calculated hash value.
177  */
178 static inline uint32_t
179 rte_hash_crc(const void *data, uint32_t data_len, uint32_t init_val)
180 {
181         unsigned i;
182         uintptr_t pd = (uintptr_t) data;
183
184         for (i = 0; i < data_len / 8; i++) {
185                 init_val = rte_hash_crc_8byte(*(const uint64_t *)pd, init_val);
186                 pd += 8;
187         }
188
189         if (data_len & 0x4) {
190                 init_val = rte_hash_crc_4byte(*(const uint32_t *)pd, init_val);
191                 pd += 4;
192         }
193
194         if (data_len & 0x2) {
195                 init_val = rte_hash_crc_2byte(*(const uint16_t *)pd, init_val);
196                 pd += 2;
197         }
198
199         if (data_len & 0x1)
200                 init_val = rte_hash_crc_1byte(*(const uint8_t *)pd, init_val);
201
202         return init_val;
203 }
204
205 #ifdef __cplusplus
206 }
207 #endif
208
209 #endif /* _RTE_HASH_CRC_H_ */