Skip to content

Feat/matching round2 - #10

Merged
jcfangc merged 8 commits into
mainfrom
feat/matching-round2
Jun 21, 2026
Merged

Feat/matching round2#10
jcfangc merged 8 commits into
mainfrom
feat/matching-round2

Conversation

@jcfangc

@jcfangc jcfangc commented Jun 21, 2026

Copy link
Copy Markdown
Owner

No description provided.

jcfangc and others added 8 commits June 20, 2026 23:55
Replace the scalar per-element loop in the NEON backend of
eq_words_unaligned with true 2-lane SIMD: vld1q_u64 loads,
vshlq_u64 (variable shift, negative = logical right), vorrq_u64
for window construction, and vceqq_u64 for parallel comparison.

Previously the NEON backend iterated with 'while i + 2 <= len'
but computed each 64-bit window one at a time via scalar shift
and OR, matching neither SSE2 nor AVX2 which use parallel
_mm_srl_epi64 / _mm_sll_epi64.

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: DeepSeek AI <service@deepseek.com>
Rust 2024 requires explicit unsafe {} blocks for unsafe intrinsics
inside unsafe fn bodies. These two vld1q_u64 calls in the NEON
backends of funcs_for_find_core and funcs_for_rfind_core were
missing the unsafe block.

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: DeepSeek AI <service@deepseek.com>
Refactor matches_at to reuse the existing SIMD word-equality backends:
- Word-aligned offsets (shift == 0): delegate to starts_with_words
- Unaligned offsets: delegate to ends_with_words (shifted-window SIMD)

Previously matches_at always took the scalar bits_equal_at path.
The remainder (partial word) handling mirrors the ends_with pattern.

Also add doc comments to all three methods.

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: DeepSeek AI <service@deepseek.com>
When full_words < SMALL_WORDS, bypass the shift/base_word/slice
setup and delegate directly to the scalar bits_equal_at. The
underlying starts_with_words/ends_with_words already have the
same guard internally, but checking at the matches_at level
avoids computing shift, base_word, and the word slice.

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: DeepSeek AI <service@deepseek.com>
…ends

The scalar rfind computes max_shift = min(last_start - base, 63)
as the maximum shift value (0..=63). The SIMD backends compute
min(64, last_start - base + 1) as a count (1..=64), then round
up to a LANES multiple (2 or 4). Out-of-range positions are
guarded by the pos <= last_start check in the verify loop.

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: DeepSeek AI <service@deepseek.com>
Move bits_equal_at from a private free function in impls_for_matching
to a pub(crate) method on BitString in impls_for_matches_at, giving it
direct access to starts_with_words / ends_with_words.

The method now uses SIMD word-equality for long patterns
(full_words >= SMALL_WORDS) and scalar comparison for short ones.
matches_at simplifies to a thin guard-and-delegate wrapper.

All call sites updated: find/rfind/contains verify closures, backend
equivalence tests, and bits_equal_at unit tests.

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: DeepSeek AI <service@deepseek.com>
When the pattern fits in a single u64 (<= 64 bits), skip the
full_words / SMALL_WORDS / SIMD dispatch and use a single
read_word_at + mask + compare. This eliminates branching and
loop overhead for the common short-pattern case.

starts_with now beats String in small scenarios (5.0ns vs 6.9ns).

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: DeepSeek AI <service@deepseek.com>
Move empty-pattern guards above all variable bindings in
bits_equal_at, starts_with, and ends_with. This makes the
early-return intent obvious and avoids computing needle_words,
sw, shift, base_word, etc. just to find mask == 0.

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: DeepSeek AI <service@deepseek.com>
@codecov-commenter

Copy link
Copy Markdown

⚠️ Please install the 'codecov app svg image' to ensure uploads and comments are reliably processed by Codecov.

Codecov Report

❌ Patch coverage is 64.10256% with 28 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
..._string/impls_for_matching/impls_for_matches_at.rs 53.44% 27 Missing ⚠️
...rc/bit_string/impls_for_matching/impls_for_find.rs 80.00% 1 Missing ⚠️

📢 Thoughts on this report? Let us know!

@codspeed-hq

codspeed-hq Bot commented Jun 21, 2026

Copy link
Copy Markdown

Merging this PR will improve performance by 60.69%

⚡ 7 improved benchmarks
✅ 85 untouched benchmarks
🆕 8 new benchmarks
⏩ 11 skipped benchmarks1

Performance Changes

Benchmark BASE HEAD Efficiency
starts_with/len_65/yes/bit_string 495.3 ns 216.1 ns ×2.3
starts_with/len_65/no/bit_string 524.4 ns 245.3 ns ×2.1
ends_with/len_65/no/bit_string 562.8 ns 279.7 ns ×2
ends_with/len_65/yes/bit_string 562.8 ns 279.7 ns ×2
count_ones/len_65/alternating/bit_string 277.8 ns 248.6 ns +11.73%
count_ones/len_65/dense/bit_string 277.8 ns 248.6 ns +11.73%
count_ones/len_65/sparse/bit_string 277.8 ns 248.6 ns +11.73%
🆕 matches_at/len_65/no/aligned/bit_string N/A 338.3 ns N/A
🆕 matches_at/len_65/no/unaligned/bit_string N/A 341.1 ns N/A
🆕 matches_at/len_65/yes/aligned/bit_string N/A 338.3 ns N/A
🆕 matches_at/len_65/yes/unaligned/bit_string N/A 341.1 ns N/A
🆕 matches_at/len_65536/no/aligned/bit_string N/A 621.7 ns N/A
🆕 matches_at/len_65536/no/unaligned/bit_string N/A 656.7 ns N/A
🆕 matches_at/len_65536/yes/aligned/bit_string N/A 623.9 ns N/A
🆕 matches_at/len_65536/yes/unaligned/bit_string N/A 690.6 ns N/A

Tip

Curious why this is faster? Comment @codspeedbot explain why this is faster on this PR, or directly use the CodSpeed MCP with your agent.


Comparing feat/matching-round2 (5429390) with main (defdf59)

Open in CodSpeed

Footnotes

  1. 11 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

@jcfangc
jcfangc merged commit 73f8822 into main Jun 21, 2026
7 checks passed
@jcfangc
jcfangc deleted the feat/matching-round2 branch June 21, 2026 01:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants