Line data Source code
1 : /*
2 : * libpino - bswap.h
3 : *
4 : * This file is part of libpino.
5 : *
6 : * Author: Go Kudo <zeriyoshi@gmail.com>
7 : * SPDX-License-Identifier: MIT
8 : */
9 :
10 : #ifndef PINO_INTERNAL_BSWAP_H
11 : #define PINO_INTERNAL_BSWAP_H
12 :
13 : #include <stddef.h>
14 : #include <stdint.h>
15 : #include <string.h>
16 :
17 : #include <pino/portable.h>
18 :
19 : #if PINO_USE_SIMD
20 : #include "simd.h"
21 : #endif
22 :
23 49 : static inline void *pino_bswap_memcpy(void *dest, const void *src, size_t size, size_t elem_size)
24 : {
25 : const uint8_t *sp;
26 : uint64_t *dest64, *src64;
27 : uint32_t *dest32, *src32;
28 : uint16_t *dest16, *src16;
29 : uint8_t *dp;
30 : size_t i, j, num_elements;
31 :
32 : #if PINO_USE_SIMD && defined(PINO_SIMD_AVX2)
33 : __m256i shuffle_mask, data;
34 : size_t simd_elements;
35 :
36 49 : dp = (uint8_t *)dest;
37 49 : sp = (const uint8_t *)src;
38 :
39 49 : if (elem_size == 1 || size == 0) {
40 4 : return memcpy(dest, src, size);
41 : }
42 :
43 45 : if (size % elem_size != 0) {
44 1 : return memcpy(dest, src, size);
45 : }
46 :
47 44 : if (elem_size == 2 && (((uintptr_t)dest | (uintptr_t)src) & 0x1) == 0) {
48 6 : dest16 = (uint16_t *)dest;
49 6 : src16 = (uint16_t *)src;
50 6 : num_elements = size / 2;
51 :
52 90 : for (i = 0; i < num_elements; i++) {
53 84 : dest16[i] = pino_bswap16(src16[i]);
54 : }
55 :
56 6 : return dest;
57 38 : } else if (elem_size == 4 && (((uintptr_t)dest | (uintptr_t)src) & 0x3) == 0) {
58 23 : dest32 = (uint32_t *)dest;
59 23 : src32 = (uint32_t *)src;
60 23 : num_elements = size / 4;
61 :
62 23 : simd_elements = num_elements / 8;
63 :
64 23 : if (simd_elements > 0) {
65 6 : shuffle_mask = _mm256_set_epi8(28, 29, 30, 31, 24, 25, 26, 27, 20, 21, 22, 23, 16, 17, 18, 19, 12, 13, 14,
66 : 15, 8, 9, 10, 11, 4, 5, 6, 7, 0, 1, 2, 3);
67 :
68 24 : for (i = 0; i < simd_elements; i++) {
69 36 : data = _mm256_loadu_si256((__m256i *)(src32 + i * 8));
70 18 : data = _mm256_shuffle_epi8(data, shuffle_mask);
71 18 : _mm256_storeu_si256((__m256i *)(dest32 + i * 8), data);
72 : }
73 :
74 6 : i = simd_elements * 8;
75 : } else {
76 17 : i = 0;
77 : }
78 :
79 47 : for (; i < num_elements; i++) {
80 24 : dest32[i] = pino_bswap32(src32[i]);
81 : }
82 :
83 23 : return dest;
84 15 : } else if (elem_size == 8 && (((uintptr_t)dest | (uintptr_t)src) & 0x7) == 0) {
85 12 : dest64 = (uint64_t *)dest;
86 12 : src64 = (uint64_t *)src;
87 12 : num_elements = size / 8;
88 :
89 12 : simd_elements = num_elements / 4;
90 :
91 12 : if (simd_elements > 0) {
92 5 : shuffle_mask = _mm256_set_epi8(24, 25, 26, 27, 28, 29, 30, 31, 16, 17, 18, 19, 20, 21, 22, 23, 8, 9, 10, 11,
93 : 12, 13, 14, 15, 0, 1, 2, 3, 4, 5, 6, 7);
94 :
95 21 : for (i = 0; i < simd_elements; i++) {
96 32 : data = _mm256_loadu_si256((__m256i *)(src64 + i * 4));
97 16 : data = _mm256_shuffle_epi8(data, shuffle_mask);
98 16 : _mm256_storeu_si256((__m256i *)(dest64 + i * 4), data);
99 : }
100 :
101 5 : i = simd_elements * 4;
102 : } else {
103 7 : i = 0;
104 : }
105 :
106 22 : for (; i < num_elements; i++) {
107 10 : dest64[i] = pino_bswap64(src64[i]);
108 : }
109 :
110 12 : return dest;
111 : }
112 :
113 3 : num_elements = size / elem_size;
114 13 : for (i = 0; i < num_elements; i++) {
115 46 : for (j = 0; j < elem_size; j++) {
116 36 : dp[i * elem_size + j] = sp[i * elem_size + (elem_size - 1 - j)];
117 : }
118 : }
119 :
120 3 : return dest;
121 :
122 : #elif PINO_USE_SIMD && defined(PINO_SIMD_NEON)
123 : uint16x8_t data16;
124 : uint32x4_t data32;
125 : uint64x2_t data64;
126 : size_t simd_elements;
127 :
128 : dp = (uint8_t *)dest;
129 : sp = (const uint8_t *)src;
130 :
131 : if (elem_size == 1 || size == 0) {
132 : return memcpy(dest, src, size);
133 : }
134 :
135 : if (size % elem_size != 0) {
136 : return memcpy(dest, src, size);
137 : }
138 :
139 : if (elem_size == 2 && (((uintptr_t)dest | (uintptr_t)src) & 0x1) == 0) {
140 : dest16 = (uint16_t *)dest;
141 : src16 = (uint16_t *)src;
142 : num_elements = size / 2;
143 :
144 : simd_elements = num_elements / 8;
145 :
146 : for (i = 0; i < simd_elements; i++) {
147 : data16 = vld1q_u16(src16 + i * 8);
148 : data16 = vreinterpretq_u16_u8(vrev16q_u8(vreinterpretq_u8_u16(data16)));
149 : vst1q_u16(dest16 + i * 8, data16);
150 : }
151 :
152 : i = simd_elements * 8;
153 : for (; i < num_elements; i++) {
154 : dest16[i] = pino_bswap16(src16[i]);
155 : }
156 :
157 : return dest;
158 : } else if (elem_size == 4 && (((uintptr_t)dest | (uintptr_t)src) & 0x3) == 0) {
159 : dest32 = (uint32_t *)dest;
160 : src32 = (uint32_t *)src;
161 : num_elements = size / 4;
162 :
163 : simd_elements = num_elements / 4;
164 :
165 : for (i = 0; i < simd_elements; i++) {
166 : data32 = vld1q_u32(src32 + i * 4);
167 : data32 = vreinterpretq_u32_u8(vrev32q_u8(vreinterpretq_u8_u32(data32)));
168 : vst1q_u32(dest32 + i * 4, data32);
169 : }
170 :
171 : i = simd_elements * 4;
172 : for (; i < num_elements; i++) {
173 : dest32[i] = pino_bswap32(src32[i]);
174 : }
175 :
176 : return dest;
177 : } else if (elem_size == 8 && (((uintptr_t)dest | (uintptr_t)src) & 0x7) == 0) {
178 : dest64 = (uint64_t *)dest;
179 : src64 = (uint64_t *)src;
180 : num_elements = size / 8;
181 :
182 : simd_elements = num_elements / 2;
183 :
184 : for (i = 0; i < simd_elements; i++) {
185 : data64 = vld1q_u64(src64 + i * 2);
186 : data64 = vreinterpretq_u64_u8(vrev64q_u8(vreinterpretq_u8_u64(data64)));
187 : vst1q_u64(dest64 + i * 2, data64);
188 : }
189 :
190 : i = simd_elements * 2;
191 : for (; i < num_elements; i++) {
192 : dest64[i] = pino_bswap64(src64[i]);
193 : }
194 :
195 : return dest;
196 : }
197 :
198 : num_elements = size / elem_size;
199 : for (i = 0; i < num_elements; i++) {
200 : for (j = 0; j < elem_size; j++) {
201 : dp[i * elem_size + j] = sp[i * elem_size + (elem_size - 1 - j)];
202 : }
203 : }
204 :
205 : return dest;
206 :
207 : #elif PINO_USE_SIMD && defined(PINO_SIMD_WASM)
208 : v128_t data;
209 : size_t simd_elements;
210 :
211 : dp = (uint8_t *)dest;
212 : sp = (const uint8_t *)src;
213 :
214 : if (elem_size == 1 || size == 0) {
215 : return memcpy(dest, src, size);
216 : }
217 :
218 : if (size % elem_size != 0) {
219 : return memcpy(dest, src, size);
220 : }
221 :
222 : if (elem_size == 2 && (((uintptr_t)dest | (uintptr_t)src) & 0x1) == 0) {
223 : dest16 = (uint16_t *)dest;
224 : src16 = (uint16_t *)src;
225 : num_elements = size / 2;
226 :
227 : for (i = 0; i < num_elements; i++) {
228 : dest16[i] = pino_bswap16(src16[i]);
229 : }
230 :
231 : return dest;
232 : } else if (elem_size == 4 && (((uintptr_t)dest | (uintptr_t)src) & 0x3) == 0) {
233 : dest32 = (uint32_t *)dest;
234 : src32 = (uint32_t *)src;
235 : num_elements = size / 4;
236 :
237 : simd_elements = num_elements / 4;
238 :
239 : if (simd_elements > 0) {
240 : for (i = 0; i < simd_elements; i++) {
241 : data = wasm_v128_load(src32 + i * 4);
242 : data = wasm_i8x16_shuffle(data, data, 3, 2, 1, 0, 7, 6, 5, 4, 11, 10, 9, 8, 15, 14, 13, 12);
243 : wasm_v128_store(dest32 + i * 4, data);
244 : }
245 :
246 : i = simd_elements * 4;
247 : } else {
248 : i = 0;
249 : }
250 :
251 : for (; i < num_elements; i++) {
252 : dest32[i] = pino_bswap32(src32[i]);
253 : }
254 :
255 : return dest;
256 : } else if (elem_size == 8 && (((uintptr_t)dest | (uintptr_t)src) & 0x7) == 0) {
257 : dest64 = (uint64_t *)dest;
258 : src64 = (uint64_t *)src;
259 : num_elements = size / 8;
260 :
261 : simd_elements = num_elements / 2;
262 :
263 : if (simd_elements > 0) {
264 : for (i = 0; i < simd_elements; i++) {
265 : data = wasm_v128_load(src64 + i * 2);
266 : data = wasm_i8x16_shuffle(data, data, 7, 6, 5, 4, 3, 2, 1, 0, 15, 14, 13, 12, 11, 10, 9, 8);
267 : wasm_v128_store(dest64 + i * 2, data);
268 : }
269 :
270 : i = simd_elements * 2;
271 : } else {
272 : i = 0;
273 : }
274 :
275 : for (; i < num_elements; i++) {
276 : dest64[i] = pino_bswap64(src64[i]);
277 : }
278 :
279 : return dest;
280 : }
281 :
282 : num_elements = size / elem_size;
283 : for (i = 0; i < num_elements; i++) {
284 : for (j = 0; j < elem_size; j++) {
285 : dp[i * elem_size + j] = sp[i * elem_size + (elem_size - 1 - j)];
286 : }
287 : }
288 :
289 : return dest;
290 :
291 : #else
292 :
293 : dp = (uint8_t *)dest;
294 : sp = (const uint8_t *)src;
295 :
296 : if (elem_size == 1 || size == 0) {
297 : return memcpy(dest, src, size);
298 : }
299 :
300 : if (size % elem_size != 0) {
301 : return memcpy(dest, src, size);
302 : }
303 :
304 : if (elem_size == 2 && (((uintptr_t)dest | (uintptr_t)src) & 0x1) == 0) {
305 : dest16 = (uint16_t *)dest;
306 : src16 = (uint16_t *)src;
307 : num_elements = size / 2;
308 :
309 : for (i = 0; i < num_elements; i++) {
310 : dest16[i] = pino_bswap16(src16[i]);
311 : }
312 :
313 : return dest;
314 : } else if (elem_size == 4 && (((uintptr_t)dest | (uintptr_t)src) & 0x3) == 0) {
315 : dest32 = (uint32_t *)dest;
316 : src32 = (uint32_t *)src;
317 : num_elements = size / 4;
318 :
319 : for (i = 0; i < num_elements; i++) {
320 : dest32[i] = pino_bswap32(src32[i]);
321 : }
322 :
323 : return dest;
324 : } else if (elem_size == 8 && (((uintptr_t)dest | (uintptr_t)src) & 0x7) == 0) {
325 : dest64 = (uint64_t *)dest;
326 : src64 = (uint64_t *)src;
327 : num_elements = size / 8;
328 :
329 : for (i = 0; i < num_elements; i++) {
330 : dest64[i] = pino_bswap64(src64[i]);
331 : }
332 :
333 : return dest;
334 : }
335 :
336 : num_elements = size / elem_size;
337 : for (i = 0; i < num_elements; i++) {
338 : for (j = 0; j < elem_size; j++) {
339 : dp[i * elem_size + j] = sp[i * elem_size + (elem_size - 1 - j)];
340 : }
341 : }
342 :
343 : return dest;
344 : #endif
345 : }
346 :
347 : #endif /* PINO_INTERNAL_BSWAP_H */
|