Use new simd library for scanning string literals

This commit is contained in:
2025-06-04 13:49:19 -04:00
parent b5f41768a7
commit 3e2f830d0b
4 changed files with 112165 additions and 82 deletions

View File

@@ -1,6 +1,5 @@
#pragma once
#include <bit>
#include <cassert>
#include <cctype>
#include <cstdint>
@@ -9,15 +8,9 @@
#include <initializer_list>
#include <tuple>
#ifdef __x86_64__
#include <immintrin.h>
#endif
#ifdef __aarch64__
#include <arm_neon.h>
#endif
#include "musttail.h"
#include "preserve_none.h"
#include "simd.h"
#include "tables.h"
#include "weaseljson.h"
@@ -409,64 +402,26 @@ inline PRESERVE_NONE WeaselJsonStatus n_string(Parser3 *self) {
inline PRESERVE_NONE WeaselJsonStatus n_string2(Parser3 *self) {
const auto before = self->buf;
// Advance self->buf to the first "non-normal" character
#ifdef __x86_64__
// Advance self->buf to the first "non-normal" character
for (;;) {
if (self->bufEnd - self->buf < 16) [[unlikely]] {
constexpr int kStride = 64;
if (self->bufEnd - self->buf < kStride) [[unlikely]] {
while (self->buf != self->bufEnd &&
tables.stringByteMeaning[uint8_t(*self->buf)] == Tables::NORMAL) {
++self->buf;
}
break;
}
__m128i x;
memcpy(&x, self->buf, 16);
const uint32_t dubquote =
_mm_movemask_epi8(_mm_cmpeq_epi8(_mm_set1_epi8('"'), x));
const uint32_t backslash =
_mm_movemask_epi8(_mm_cmpeq_epi8(_mm_set1_epi8('\\'), x));
const uint32_t control_or_negative =
_mm_movemask_epi8(_mm_cmpgt_epi8(_mm_set1_epi8(0x20), x));
const uint32_t non_normal = dubquote | backslash | control_or_negative;
if (non_normal) {
self->buf += std::countr_zero(non_normal);
using V = simd<int8_t, kStride>;
auto v = V{(int8_t *)self->buf};
int normal =
(v != V::splat('"') & v != V::splat('\\') & v >= V::splat(0x20))
.count_leading_nonzero_lanes();
self->buf += normal;
if (normal < kStride) {
break;
}
self->buf += 16;
}
#elif defined(__aarch64__)
for (;;) {
if (self->bufEnd - self->buf < 16) [[unlikely]] {
while (self->buf != self->bufEnd &&
tables.stringByteMeaning[uint8_t(*self->buf)] == Tables::NORMAL) {
++self->buf;
}
break;
}
int8x16_t x;
memcpy(&x, self->buf, 16);
const auto dubquote = vreinterpretq_s8_u8(vceqq_s8(vdupq_n_s8('"'), x));
const auto backslash = vreinterpretq_s8_u8(vceqq_s8(vdupq_n_s8('\\'), x));
const auto control_or_negative =
vreinterpretq_s8_u8(vcgtq_s8(vdupq_n_s8(0x20), x));
const auto non_normal = vget_lane_u64(
vreinterpret_u64_u8(vshrn_n_u16(
vreinterpretq_u16_s8(
vorrq_s8(vorrq_s8(dubquote, backslash), control_or_negative)),
4)),
0);
if (non_normal) {
self->buf += std::countr_zero(non_normal) / 4;
break;
}
self->buf += 16;
}
#else
while (self->buf != self->bufEnd &&
tables.stringByteMeaning[uint8_t(*self->buf)] == Tables::NORMAL) {
++self->buf;
}
#endif
int len = self->buf - before;
memmove(self->writeBuf, before, len);