cwist
Modern C web framework with libttak runtime
Loading...
Searching...
No Matches
simd_parser.h
Go to the documentation of this file.
1#ifndef __CWIST_SIMD_PARSER_H__
2#define __CWIST_SIMD_PARSER_H__
3
4#include <stddef.h>
5#include <stdint.h>
6#include <stdbool.h>
7#include <string.h>
8
9#if defined(__x86_64__) || defined(_M_X64) || defined(__i386__) || defined(_M_IX86)
10#if defined(__AVX2__)
11#include <immintrin.h>
12#define CWIST_SIMD_AVX2 1
13#endif
14#if defined(__SSE4_2__)
15#include <nmmintrin.h>
16#define CWIST_SIMD_SSE42 1
17#endif
18#if defined(__SSE2__) || defined(_M_AMD64) || defined(_M_X64)
19#include <emmintrin.h>
20#define CWIST_SIMD_SSE2 1
21#endif
22#elif defined(__ARM_NEON) || defined(__ARM_NEON__) || defined(__aarch64__)
23#include <arm_neon.h>
24#define CWIST_SIMD_NEON 1
25#elif (defined(__riscv) || defined(__riscv__)) && defined(__riscv_vector)
26#include <riscv_vector.h>
27#define CWIST_SIMD_RISCV_VECTOR 1
28#elif (defined(__powerpc__) || defined(__ppc__) || defined(__PPC__) || defined(__PPC64__) || \
29 defined(__ppc64le__) || defined(_ARCH_PPC)) && \
30 (defined(__ALTIVEC__) || defined(__VSX__))
31#include <altivec.h>
32#undef vector
33#undef pixel
34#undef bool
35#define CWIST_SIMD_PPC_ALTIVEC 1
36#elif (defined(__mips__) || defined(__mips64) || defined(__mips64__) || defined(__mips_msa)) && \
37 defined(__mips_msa)
38#include <msa.h>
39#define CWIST_SIMD_MIPS_MSA 1
40#endif
41
49static inline const char *cwist_simd_find_char(const char *buf, size_t len, char c) {
50 if (!buf || len == 0) return NULL;
51
52 size_t i = 0;
53
54#if defined(CWIST_SIMD_AVX2)
56 while (i + 32 <= len) {
57 __m256i chunk = _mm256_loadu_si256((const __m256i *)(const void *)(buf + i));
60 if (mask != 0) {
61 return buf + i + __builtin_ctz(mask);
62 }
63 i += 32;
64 }
65#elif defined(CWIST_SIMD_SSE2)
67 while (i + 16 <= len) {
68 __m128i chunk = _mm_loadu_si128((const __m128i *)(const void *)(buf + i));
71 if (mask != 0) {
72 return buf + i + __builtin_ctz(mask);
73 }
74 i += 16;
75 }
76#elif defined(CWIST_SIMD_NEON)
78#if defined(__aarch64__)
79 while (i + 32 <= len) {
80 uint8x16_t chunk0 = vld1q_u8((const uint8_t *)(buf + i));
81 uint8x16_t chunk1 = vld1q_u8((const uint8_t *)(buf + i + 16));
85 if (vmaxvq_u8(combined) != 0) {
86 for (size_t k = 0; k < 32; k++) {
87 if (buf[i + k] == c) return buf + i + k;
88 }
89 }
90 i += 32;
91 }
92#endif
93 while (i + 16 <= len) {
94 uint8x16_t chunk = vld1q_u8((const uint8_t *)(buf + i));
96#if defined(__aarch64__)
97 if (vmaxvq_u8(cmp) != 0) {
98 for (size_t k = 0; k < 16; k++) {
99 if (buf[i + k] == c) return buf + i + k;
100 }
101 }
102#else
104 if (vgetq_lane_u64(cmp64, 0) != 0 || vgetq_lane_u64(cmp64, 1) != 0) {
105 for (size_t k = 0; k < 16; k++) {
106 if (buf[i + k] == c) return buf + i + k;
107 }
108 }
109#endif
110 i += 16;
111 }
112#elif defined(CWIST_SIMD_RISCV_VECTOR)
113 size_t vl;
114 while (i < len) {
115 vl = __riscv_vsetvl_e8m1(len - i);
116 vuint8m1_t chunk = __riscv_vle8_v_u8m1((const uint8_t *)(buf + i), vl);
119 if (first >= 0) {
120 return buf + i + first;
121 }
122 i += vl;
123 }
124#elif defined(CWIST_SIMD_PPC_ALTIVEC)
125 __vector unsigned char target = vec_splats((unsigned char)c);
126 while (i + 16 <= len) {
127 __vector unsigned char chunk;
128 memcpy(&chunk, buf + i, 16);
129 if (vec_any_eq(chunk, target)) {
130 for (size_t k = 0; k < 16; k++) {
131 if (buf[i + k] == c) return buf + i + k;
132 }
133 }
134 i += 16;
135 }
136#elif defined(CWIST_SIMD_MIPS_MSA)
137 v16u8 target = (v16u8)__builtin_msa_fill_b((unsigned char)c);
138 while (i + 16 <= len) {
139 v16u8 chunk;
140 memcpy(&chunk, buf + i, 16);
143 for (size_t k = 0; k < 16; k++) {
144 if (buf[i + k] == c) return buf + i + k;
145 }
146 }
147 i += 16;
148 }
149#endif
150
151 /* 64-bit SWAR (SIMD Within A Register) fast loop for 64-bit architectures */
152#if defined(__SIZEOF_POINTER__) && __SIZEOF_POINTER__ == 8
153 uint64_t target64 = ((uint8_t)c) * 0x0101010101010101ULL;
154 while (i + 8 <= len) {
156 memcpy(&chunk64, buf + i, sizeof(chunk64));
158 uint64_t has_zero = (xor_val - 0x0101010101010101ULL) & ~xor_val & 0x8080808080808080ULL;
159 if (has_zero != 0) {
160 for (size_t k = 0; k < 8; k++) {
161 if (buf[i + k] == c) return buf + i + k;
162 }
163 }
164 i += 8;
165 }
166#endif
167
168 /* Scalar fallback for remaining bytes */
169 if (i < len) {
170 return (const char *)memchr(buf + i, (int)(unsigned char)c, len - i);
171 }
172 return NULL;
173}
174
181static inline const char *cwist_simd_find_crlf(const char *buf, size_t len) {
182 if (!buf || len < 2) return NULL;
183
184 const char *curr = buf;
185 size_t remaining = len;
186
187 while (remaining >= 2) {
188 const char *cr = cwist_simd_find_char(curr, remaining, '\r');
189 if (!cr) return NULL;
190 if (cr + 1 < buf + len && cr[1] == '\n') {
191 return cr;
192 }
193 size_t consumed = (size_t)(cr + 1 - curr);
194 curr += consumed;
196 }
197 return NULL;
198}
199
206static inline const char *cwist_simd_find_crlfcrlf(const char *buf, size_t len) {
207 if (!buf || len < 4) return NULL;
208
209 size_t i = 0;
210
211 /* Paired matcher: a "\r\n\r\n" occurrence at offset j requires
212 * buf[j] == '\r' && buf[j+1] == '\n' && buf[j+2] == '\r' && buf[j+3] == '\n'
213 * Compare four unaligned loads (at j, j+1, j+2, j+3) and AND the four
214 * equality masks, so every offset is tested in a single pass with no
215 * rescan on bare-'\r' data. The unaligned load idiom matches
216 * cwist_simd_find_char above; the scalar tail below keeps the
217 * memchr/SWAR structure and covers the vector-safety margin and the
218 * non-vector architectures. */
219#if defined(CWIST_SIMD_AVX2)
220 const __m256i cr_v = _mm256_set1_epi8('\r');
221 const __m256i lf_v = _mm256_set1_epi8('\n');
222 while (i + 32 + 3 <= len) {
223 __m256i v0 = _mm256_loadu_si256((const __m256i *)(const void *)(buf + i));
224 __m256i v1 = _mm256_loadu_si256((const __m256i *)(const void *)(buf + i + 1));
225 __m256i v2 = _mm256_loadu_si256((const __m256i *)(const void *)(buf + i + 2));
226 __m256i v3 = _mm256_loadu_si256((const __m256i *)(const void *)(buf + i + 3));
231 if (mask != 0) {
232 return buf + i + __builtin_ctz(mask);
233 }
234 i += 32;
235 }
236#elif defined(CWIST_SIMD_SSE2)
237 const __m128i cr_v = _mm_set1_epi8('\r');
238 const __m128i lf_v = _mm_set1_epi8('\n');
239 while (i + 16 + 3 <= len) {
240 __m128i v0 = _mm_loadu_si128((const __m128i *)(const void *)(buf + i));
241 __m128i v1 = _mm_loadu_si128((const __m128i *)(const void *)(buf + i + 1));
242 __m128i v2 = _mm_loadu_si128((const __m128i *)(const void *)(buf + i + 2));
243 __m128i v3 = _mm_loadu_si128((const __m128i *)(const void *)(buf + i + 3));
247 if (mask != 0) {
248 return buf + i + __builtin_ctz(mask);
249 }
250 i += 16;
251 }
252#elif defined(CWIST_SIMD_NEON)
253 const uint8x16_t cr_v = vdupq_n_u8((uint8_t)'\r');
254 const uint8x16_t lf_v = vdupq_n_u8((uint8_t)'\n');
255 while (i + 16 + 3 <= len) {
256 uint8x16_t v0 = vld1q_u8((const uint8_t *)(buf + i));
257 uint8x16_t v1 = vld1q_u8((const uint8_t *)(buf + i + 1));
258 uint8x16_t v2 = vld1q_u8((const uint8_t *)(buf + i + 2));
259 uint8x16_t v3 = vld1q_u8((const uint8_t *)(buf + i + 3));
262#if defined(__aarch64__)
263 if (vmaxvq_u8(m) != 0) {
264 for (size_t k = 0; k < 16; k++) {
265 if (buf[i + k] == '\r' && buf[i + k + 1] == '\n' && buf[i + k + 2] == '\r' &&
266 buf[i + k + 3] == '\n')
267 return buf + i + k;
268 }
269 }
270#else
272 if (vgetq_lane_u64(m64, 0) != 0 || vgetq_lane_u64(m64, 1) != 0) {
273 for (size_t k = 0; k < 16; k++) {
274 if (buf[i + k] == '\r' && buf[i + k + 1] == '\n' && buf[i + k + 2] == '\r' &&
275 buf[i + k + 3] == '\n')
276 return buf + i + k;
277 }
278 }
279#endif
280 i += 16;
281 }
282#elif defined(CWIST_SIMD_RISCV_VECTOR)
283 while (len - i >= 4) {
284 size_t vl = __riscv_vsetvl_e8m1(len - i - 3);
285 if (vl == 0) break;
286 vuint8m1_t v0 = __riscv_vle8_v_u8m1((const uint8_t *)(buf + i), vl);
287 vuint8m1_t v1 = __riscv_vle8_v_u8m1((const uint8_t *)(buf + i + 1), vl);
288 vuint8m1_t v2 = __riscv_vle8_v_u8m1((const uint8_t *)(buf + i + 2), vl);
289 vuint8m1_t v3 = __riscv_vle8_v_u8m1((const uint8_t *)(buf + i + 3), vl);
294 long first = __riscv_vfirst_m_b8(m, vl);
295 if (first >= 0) {
296 return buf + i + first;
297 }
298 i += vl;
299 }
300#elif defined(CWIST_SIMD_PPC_ALTIVEC)
301 const __vector unsigned char cr_v = vec_splats((unsigned char)'\r');
302 const __vector unsigned char lf_v = vec_splats((unsigned char)'\n');
303 const __vector unsigned char zero_v = vec_splats((unsigned char)0);
304 while (i + 16 + 3 <= len) {
305 __vector unsigned char v0, v1, v2, v3;
306 memcpy(&v0, buf + i, 16);
307 memcpy(&v1, buf + i + 1, 16);
308 memcpy(&v2, buf + i + 2, 16);
309 memcpy(&v3, buf + i + 3, 16);
310 __vector unsigned char m = vec_and(vec_and(vec_cmpeq(v0, cr_v), vec_cmpeq(v1, lf_v)),
312 if (!vec_all_eq(m, zero_v)) {
313 for (size_t k = 0; k < 16; k++) {
314 if (buf[i + k] == '\r' && buf[i + k + 1] == '\n' && buf[i + k + 2] == '\r' &&
315 buf[i + k + 3] == '\n')
316 return buf + i + k;
317 }
318 }
319 i += 16;
320 }
321#elif defined(CWIST_SIMD_MIPS_MSA)
322 v16u8 cr_v = (v16u8)__builtin_msa_fill_b((unsigned char)'\r');
323 v16u8 lf_v = (v16u8)__builtin_msa_fill_b((unsigned char)'\n');
324 while (i + 16 + 3 <= len) {
325 v16u8 v0, v1, v2, v3;
326 memcpy(&v0, buf + i, 16);
327 memcpy(&v1, buf + i + 1, 16);
328 memcpy(&v2, buf + i + 2, 16);
329 memcpy(&v3, buf + i + 3, 16);
335 if (__builtin_msa_bnz_b(m)) {
336 for (size_t k = 0; k < 16; k++) {
337 if (buf[i + k] == '\r' && buf[i + k + 1] == '\n' && buf[i + k + 2] == '\r' &&
338 buf[i + k + 3] == '\n')
339 return buf + i + k;
340 }
341 }
342 i += 16;
343 }
344#endif
345
346 /* Scalar tail: memchr-driven (with the 64-bit SWAR loop inside
347 * cwist_simd_find_char) over the remaining bytes. */
348 const char *curr = buf + i;
349 size_t remaining = len - i;
350
351 while (remaining >= 4) {
352 const char *cr = cwist_simd_find_char(curr, remaining, '\r');
353 if (!cr) return NULL;
354 if (cr + 3 < buf + len && cr[1] == '\n' && cr[2] == '\r' && cr[3] == '\n') {
355 return cr;
356 }
357 size_t consumed = (size_t)(cr + 1 - curr);
358 curr += consumed;
360 }
361 return NULL;
362}
363
364#endif /* __CWIST_SIMD_PARSER_H__ */
size_t cap
Definition otel.c:56