Skip to content

Commit 74bb90a

Browse files
authored
SWAR-optimize ASCII fast paths in String.length and String.slice (#15255)
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 erlang/otp#10948).
1 parent 5d794ab commit 74bb90a

1 file changed

Lines changed: 20 additions & 1 deletion

File tree

lib/elixir/lib/string.ex

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2290,6 +2290,19 @@ defmodule String do
22902290
end
22912291
end
22922292

2293+
# 56-bit SWAR guard: all 7 bytes are ASCII (< 128) and none is \r (0x0D).
2294+
# Uses Mycroft's zero-byte detection: XOR with 0x0D and check for zero bytes.
2295+
defguardp ascii_no_cr_swar?(w)
2296+
when Bitwise.band(w, 0x80808080808080) == 0 and
2297+
Bitwise.band(
2298+
Bitwise.bxor(w, 0x0D0D0D0D0D0D0D) - 0x01010101010101,
2299+
0x80808080808080
2300+
) == 0
2301+
2302+
defp skip_length(<<w::56, b, rest::binary>>, acc)
2303+
when b <= 127 and b != ?\r and ascii_no_cr_swar?(w),
2304+
do: skip_length(rest, acc + 8)
2305+
22932306
defp skip_length(<<byte, rest::binary>>, acc)
22942307
when byte <= 127 and byte != ?\r,
22952308
do: skip_length(rest, acc + 1)
@@ -3213,7 +3226,13 @@ defmodule String do
32133226
byte_size_unicode(unicode)
32143227
end
32153228

3216-
defp byte_size_remaining_at(unicode, n) do
3229+
defp byte_size_remaining_at(<<byte1, byte2, rest::binary>> = binary, n)
3230+
when n > 0 and byte1 <= 127 and byte1 != ?\r and byte2 <= 127 and byte2 != ?\r do
3231+
skip = min(skip_length(rest, 1), n)
3232+
byte_size_remaining_at(binary_part(binary, skip, byte_size(binary) - skip), n - skip)
3233+
end
3234+
3235+
defp byte_size_remaining_at(unicode, n) when n > 0 do
32173236
case :unicode_util.gc(unicode) do
32183237
[_] -> 0
32193238
[_ | rest] -> byte_size_remaining_at(rest, n - 1)

0 commit comments

Comments
 (0)