From 7c587afb2ea2d06302bfdaeafd4e452cd864ef1c Mon Sep 17 00:00:00 2001 From: Nelson Vides Date: Thu, 9 Apr 2026 18:13:07 +0200 Subject: [PATCH] SWAR-optimize ASCII fast paths in String.length/1 and String.slice Add 56-bit SWAR (SIMD Within A Register) acceleration to skip_length/2 and byte_size_remaining_at/2, processing 8 ASCII bytes per iteration instead of one. Uses the Mycroft zero-byte detection algorithm to validate that 7+1 bytes are all ASCII with no \r in a single guard. This mirrors the approach taken in OTP's string module (OTP https://github.com/erlang/otp/pull/10948). --- lib/elixir/lib/string.ex | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/lib/elixir/lib/string.ex b/lib/elixir/lib/string.ex index f851f2ae63e..79178427ec6 100644 --- a/lib/elixir/lib/string.ex +++ b/lib/elixir/lib/string.ex @@ -2290,6 +2290,19 @@ defmodule String do end end + # 56-bit SWAR guard: all 7 bytes are ASCII (< 128) and none is \r (0x0D). + # Uses Mycroft's zero-byte detection: XOR with 0x0D and check for zero bytes. + defguardp ascii_no_cr_swar?(w) + when Bitwise.band(w, 0x80808080808080) == 0 and + Bitwise.band( + Bitwise.bxor(w, 0x0D0D0D0D0D0D0D) - 0x01010101010101, + 0x80808080808080 + ) == 0 + + defp skip_length(<>, acc) + when b <= 127 and b != ?\r and ascii_no_cr_swar?(w), + do: skip_length(rest, acc + 8) + defp skip_length(<>, acc) when byte <= 127 and byte != ?\r, do: skip_length(rest, acc + 1) @@ -3213,7 +3226,13 @@ defmodule String do byte_size_unicode(unicode) end - defp byte_size_remaining_at(unicode, n) do + defp byte_size_remaining_at(<> = binary, n) + when n > 0 and byte1 <= 127 and byte1 != ?\r and byte2 <= 127 and byte2 != ?\r do + skip = min(skip_length(rest, 1), n) + byte_size_remaining_at(binary_part(binary, skip, byte_size(binary) - skip), n - skip) + end + + defp byte_size_remaining_at(unicode, n) when n > 0 do case :unicode_util.gc(unicode) do [_] -> 0 [_ | rest] -> byte_size_remaining_at(rest, n - 1)