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
49
static
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)
55
__m256i
target
=
_mm256_set1_epi8
(
c
);
56
while
(
i
+ 32 <= len) {
57
__m256i
chunk
=
_mm256_loadu_si256
((
const
__m256i
*)(
const
void
*)(buf +
i
));
58
__m256i
cmp
=
_mm256_cmpeq_epi8
(
chunk
,
target
);
59
uint32_t
mask
= (
uint32_t
)
_mm256_movemask_epi8
(
cmp
);
60
if
(
mask
!= 0) {
61
return
buf +
i
+
__builtin_ctz
(
mask
);
62
}
63
i
+= 32;
64
}
65
#elif defined(CWIST_SIMD_SSE2)
66
__m128i
target
=
_mm_set1_epi8
(
c
);
67
while
(
i
+ 16 <= len) {
68
__m128i
chunk
=
_mm_loadu_si128
((
const
__m128i
*)(
const
void
*)(buf +
i
));
69
__m128i
cmp
=
_mm_cmpeq_epi8
(
chunk
,
target
);
70
uint32_t
mask
= (
uint32_t
)
_mm_movemask_epi8
(
cmp
);
71
if
(
mask
!= 0) {
72
return
buf +
i
+
__builtin_ctz
(
mask
);
73
}
74
i
+= 16;
75
}
76
#elif defined(CWIST_SIMD_NEON)
77
uint8x16_t
target
=
vdupq_n_u8
((
uint8_t
)
c
);
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));
82
uint8x16_t
cmp0
=
vceqq_u8
(
chunk0
,
target
);
83
uint8x16_t
cmp1
=
vceqq_u8
(
chunk1
,
target
);
84
uint8x16_t
combined
=
vorrq_u8
(
cmp0
,
cmp1
);
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
));
95
uint8x16_t
cmp
=
vceqq_u8
(
chunk
,
target
);
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
103
uint64x2_t
cmp64
=
vreinterpretq_u64_u8
(
cmp
);
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
);
117
vbool8_t
mask
=
__riscv_vmseq_vx_u8m1_b8
(
chunk
, (
uint8_t
)
c
,
vl
);
118
long
first
=
__riscv_vfirst_m_b8
(
mask
,
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);
141
v16u8
cmp
= (
v16u8
)
__builtin_msa_ceq_b
((
v16i8
)
chunk
, (
v16i8
)
target
);
142
if
(
__builtin_msa_bnz_b
(
cmp
)) {
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) {
155
uint64_t
chunk64
;
156
memcpy
(&
chunk64
, buf +
i
,
sizeof
(
chunk64
));
157
uint64_t
xor_val
=
chunk64
^
target64
;
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
181
static
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
;
195
remaining
-=
consumed
;
196
}
197
return
NULL
;
198
}
199
206
static
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));
227
__m256i
m
=
_mm256_and_si256
(
_mm256_cmpeq_epi8
(
v0
,
cr_v
),
_mm256_cmpeq_epi8
(
v1
,
lf_v
));
228
m
=
_mm256_and_si256
(
m
,
_mm256_cmpeq_epi8
(
v2
,
cr_v
));
229
m
=
_mm256_and_si256
(
m
,
_mm256_cmpeq_epi8
(
v3
,
lf_v
));
230
uint32_t
mask
= (
uint32_t
)
_mm256_movemask_epi8
(
m
);
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));
244
__m128i
m
=
_mm_and_si128
(
_mm_and_si128
(
_mm_cmpeq_epi8
(
v0
,
cr_v
),
_mm_cmpeq_epi8
(
v1
,
lf_v
)),
245
_mm_and_si128
(
_mm_cmpeq_epi8
(
v2
,
cr_v
),
_mm_cmpeq_epi8
(
v3
,
lf_v
)));
246
uint32_t
mask
= (
uint32_t
)
_mm_movemask_epi8
(
m
);
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));
260
uint8x16_t
m
=
vandq_u8
(
vandq_u8
(
vceqq_u8
(
v0
,
cr_v
),
vceqq_u8
(
v1
,
lf_v
)),
261
vandq_u8
(
vceqq_u8
(
v2
,
cr_v
),
vceqq_u8
(
v3
,
lf_v
)));
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
271
uint64x2_t
m64
=
vreinterpretq_u64_u8
(
m
);
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
);
290
vbool8_t
m
=
__riscv_vmand_mm
(
__riscv_vmseq_vx_u8m1_b8
(
v0
, (
uint8_t
)
'\r'
,
vl
),
291
__riscv_vmseq_vx_u8m1_b8
(
v1
, (
uint8_t
)
'\n'
,
vl
),
vl
);
292
m
=
__riscv_vmand_mm
(
m
,
__riscv_vmseq_vx_u8m1_b8
(
v2
, (
uint8_t
)
'\r'
,
vl
),
vl
);
293
m
=
__riscv_vmand_mm
(
m
,
__riscv_vmseq_vx_u8m1_b8
(
v3
, (
uint8_t
)
'\n'
,
vl
),
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
)),
311
vec_and
(
vec_cmpeq
(
v2
,
cr_v
),
vec_cmpeq
(
v3
,
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);
330
v16u8
m
= (
v16u8
)
__builtin_msa_and_v
(
331
__builtin_msa_and_v
(
__builtin_msa_ceq_b
((
v16i8
)
v0
, (
v16i8
)
cr_v
),
332
__builtin_msa_ceq_b
((
v16i8
)
v1
, (
v16i8
)
lf_v
)),
333
__builtin_msa_and_v
(
__builtin_msa_ceq_b
((
v16i8
)
v2
, (
v16i8
)
cr_v
),
334
__builtin_msa_ceq_b
((
v16i8
)
v3
, (
v16i8
)
lf_v
)));
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
;
359
remaining
-=
consumed
;
360
}
361
return
NULL
;
362
}
363
364
#endif
/* __CWIST_SIMD_PARSER_H__ */
cap
size_t cap
Definition
otel.c:56
src
net
http
simd_parser.h
Generated by
1.9.8