Skip to content

simd: mask_ternlog family + contiguous fast path for stride-4 eq masks - #301

Merged
AdaWorldAPI merged 1 commit into
masterfrom
claude/pr-294-ragged-path-validation-170zcy
Sep 4, 2026
Merged

simd: mask_ternlog family + contiguous fast path for stride-4 eq masks#301
AdaWorldAPI merged 1 commit into
masterfrom
claude/pr-294-ragged-path-validation-170zcy

Conversation

@AdaWorldAPI

@AdaWorldAPI AdaWorldAPI commented Sep 4, 2026

Copy link
Copy Markdown
Owner

What

Two additions to the mask-op family in src/simd_int_ops.rs, both consumed by lance-graph-java's lgj_hop (companion PR on the same branch name there).

1. mask_ternlog::<IMM>(a, b, c, dst) / mask_ternlog_assign::<IMM>(a, b, c)

Any 3-input Boolean function of three masks in one pass — IMM is the VPTERNLOG truth table (named tables in simd::ternlog). AND is the rank-1 member of this family: a consumer spelling a & b & c as two mask_and_assign passes through a scratch write now spends one AND3 pass (one VPTERNLOGQ per 512 bits; polyfill elsewhere via U64x8::ternlog, all arms already present from W1a-#9).

  • Tail contract stated precisely: conforming inputs → conforming dst iff IMM is even; every named immediate is; subset-shaped tables inherit mask_andnot's "subset of a" guarantee.
  • Tests: all 256 tables × 13 lengths vs an independent bit-serial reference; AND3 == and∘and (non-vacuous — both narrowers must contribute); tail-iff-even with the odd (NOR3) can-it-fire arm; length-mismatch panics for both forms.
  • Re-exported via ndarray::simd. W1a family-shape deviation recorded in .claude/blackboard.md (same rationale as mask_andnot, 2026-08-18).

2. Contiguous fast path in eq_u32_strided_to_mask

At stride_bytes == 4 the kernel gathered 16 bounds-checked scalar u32 reads into a temporary array before the U32x16 compare — a copy where a cast belonged. That is exactly the shape of every lane in a facet-major columnar store, so lance-graph-java's minor-10 store was contiguous and still being read as strided. Now one fixed [u8; 64] window per 16 elements (safe try_into, bounds proven up front) → a single vector load. Existing eq_u32_strided_stride4_matches_contiguous_primitive parity test covers it; no unsafe.

Measured

lance-graph-java columnar_hop_bench, 65 536 rows × 32 facets, equivalence asserted before timing, both changes together:

frontier before after
classid (3 933) 6 342 µs 1 203 µs
hop2 (6 943) 6 408 µs 1 101 µs
all (65 536) 7 547 µs 1 851 µs

16 MB of lane read per hop: 2.1 GB/s → ~13 GB/s.

Gates

cargo fmt --check clean · cargo clippy --lib --features std -- -D warnings clean · cargo test --lib --features std 2272 passed.

🤖 Generated with Claude Code

https://claude.ai/code/session_016WkNBjHc2e3zuyz9i8qJEv


Generated by Claude Code

Summary by CodeRabbit

  • New Features

    • Added generic three-input mask logic operations supporting all 8-bit truth tables.
    • Added in-place variants for updating existing masks.
    • Defined consistent behavior for scalar tails and input-length validation.
  • Performance

    • Improved contiguous 32-bit equality-to-mask processing with vectorized loads.
    • Reduced hop-selection processing time by combining mask operations into a single pass, with benchmarks showing up to 5.8× faster timings.
  • Compatibility

    • Existing behavior for strided inputs remains unchanged.

Two additions to the mask-op family in src/simd_int_ops.rs, both consumed
by lance-graph-java's lgj_hop:

1. mask_ternlog::<IMM>(a, b, c, dst) / mask_ternlog_assign::<IMM>(a, b, c)
   — any 3-input Boolean function of three masks in one pass, IMM being the
   VPTERNLOG truth table (named tables in simd::ternlog). AND is the rank-1
   member of this family; a consumer spelling `a & b & c` as two
   mask_and_assign passes through a scratch write now spends one AND3 pass
   (one VPTERNLOGQ per 512 bits). Tail contract: conforming inputs give a
   conforming dst iff IMM is even; every named immediate is. Parity over all
   256 tables x 13 lengths against an independent bit-serial reference,
   AND3 == and∘and (non-vacuous), tail-iff-even with the odd can-it-fire
   arm, length-mismatch panics. Re-exported via ndarray::simd. W1a family-
   shape deviation recorded in .claude/blackboard.md (same as mask_andnot).

2. eq_u32_strided_to_mask at stride_bytes == 4 gathered 16 bounds-checked
   scalar reads into a temporary before the U32x16 compare — a copy where a
   cast belonged, and exactly the shape of every lane in a facet-major
   columnar store. A contiguous path now aliases one fixed [u8; 64] window
   per 16 elements (safe try_into, bounds proven up front), which lowers to
   a single vector load. Existing stride4-vs-contiguous parity test covers
   it.

Measured through lance-graph-java's columnar_hop_bench (65 536 rows, 32
facets, both changes): lgj_hop 6.3-7.5 ms -> 1.1-1.85 ms, equivalence
asserted before timing.

Gates: cargo fmt clean; cargo clippy --lib --features std -D warnings
clean; cargo test --lib --features std 2272 passed.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016WkNBjHc2e3zuyz9i8qJEv
@coderabbitai

coderabbitai Bot commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Essentials

Run ID: a83dddec-8c01-4b8e-8ad8-f75f678a9c44

📥 Commits

Reviewing files that changed from the base of the PR and between fe509db and 1493a10.

📒 Files selected for processing (3)
  • .claude/blackboard.md
  • src/simd.rs
  • src/simd_int_ops.rs

📝 Walkthrough

Walkthrough

The SIMD API adds generic ternary mask operations with scalar-tail handling and validation. The equality-mask implementation adds a contiguous stride-4 vector-load path. Hop selection now uses one three-mask operation.

Changes

SIMD mask operations and equality optimization

Layer / File(s) Summary
Ternary mask API and validation
src/simd_int_ops.rs, src/simd.rs, .claude/blackboard.md
Added mask_ternlog and mask_ternlog_assign with compile-time truth tables, SIMD processing, scalar tails, length checks, public re-exports, tests, and one-pass AND3 hop selection.
Contiguous equality fast path
src/simd_int_ops.rs, .claude/blackboard.md
Added bounds-checked 64-byte vector loads for stride_bytes == 4. Other strided inputs retain scalar gathers.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Suggested reviewers: claude

Poem

A rabbit packs three masks in line
With truth-table bits that neatly shine
Tails hop softly, checks stand guard
Fast lanes race across the yard
One AND3 pass completes the run

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch

Comment @coderabbitai help to get the list of available commands.

@cursor

cursor Bot commented Sep 4, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_42508340-991f-44b9-afe4-cfa691036b75)

@AdaWorldAPI
AdaWorldAPI marked this pull request as ready for review September 4, 2026 21:33
@AdaWorldAPI
AdaWorldAPI merged commit d1f6a6d into master Sep 4, 2026
20 of 21 checks passed
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