Find the end of the plain run of a decoded string 16 bytes at a time with SSE2
The strings of a document that had escape sequences are written in runs without a quote, backslash, or control character; the compact dump found the end of a run 8 bytes at a time with a SWAR test. With SSE2 (x86-64) it now compares 16 bytes per step. NEON keeps the SWAR code: there the mask of a step costs more than it saves on the short runs that are typical here. Instructions of dump(), Linux (GCC 13 / Clang 18): twitter.json 1.99M -> 1.88M (-5.2 %) / 1.97M -> 1.92M (-3.0 %) CJK text with \u escapes 5.98M -> 4.52M (-24.5 %) / 5.30M -> 4.25M (-19.9 %) ASCII text with a few escapes 4.28M -> 4.09M (-4.4 %) / 4.24M -> 4.11M (-3.2 %) jeopardy (4,000 questions) 5.08M -> 4.78M (-5.8 %) / 4.97M -> 4.80M (-3.4 %) Signed-off-by: Niels Lohmann <mail@nlohmann.me>
This commit is contained in:
2 files changed
+34
-2
No files matched your search
@@ -137,9 +137,25 @@ class output_buffer
|
||||
/// image_check::bounds can have others, which are then written unchanged).
|
||||
inline std::size_t plain_output_run(const unsigned char* s, std::size_t n) noexcept
|
||||
{
|
||||
std::size_t i = 0;
|
||||
#if NLOHMANN_VIEW_SSE2
|
||||
// (16 bytes per step; with NEON, the mask of a step costs more than it saves on the
|
||||
// short runs that are typical here)
|
||||
for (; i + 16 <= n; i += 16)
|
||||
{
|
||||
const __m128i in = _mm_loadu_si128(static_cast<const __m128i*>(static_cast<const void*>(s + i))); // NOLINT(bugprone-casting-through-void)
|
||||
// (a byte is below 0x20 if it is its own minimum with 0x1F)
|
||||
const __m128i special = _mm_or_si128(_mm_or_si128(_mm_cmpeq_epi8(in, _mm_set1_epi8('"')), _mm_cmpeq_epi8(in, _mm_set1_epi8('\\'))),
|
||||
_mm_cmpeq_epi8(_mm_min_epu8(in, _mm_set1_epi8(0x1F)), in));
|
||||
const auto mask = static_cast<std::uint64_t>(static_cast<unsigned>(_mm_movemask_epi8(special)));
|
||||
if (mask != 0)
|
||||
{
|
||||
return i + static_cast<std::size_t>(count_trailing_zeros(mask));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
constexpr std::uint64_t ones = 0x0101010101010101ull;
|
||||
constexpr std::uint64_t high = 0x8080808080808080ull;
|
||||
std::size_t i = 0;
|
||||
for (; i + 8 <= n; i += 8)
|
||||
{
|
||||
const std::uint64_t v = read_eight_bytes(s + i);
|
||||
|
||||
Reference in new issue
Block a user