Skip to content

U9 × U9 head-to-head: U8×U8×sign×mul_add against U8×I8 byte-dot (probe + TurboVec-U9 handoff) - #388

Merged
AdaWorldAPI merged 11 commits into
masterfrom
claude/u9-head-to-head
Oct 29, 2026
Merged

AdaWorldAPI merged 11 commits into
masterfrom
claude/u9-head-to-head

Conversation

@AdaWorldAPI

@AdaWorldAPI AdaWorldAPI commented Oct 29, 2026 •

Copy link
Copy Markdown
Owner

Summary

This probe compares two ways of computing an exact signed 9-bit (-255..=255) dot product using only the existing ndarray::simd facade. Both read the same input per operand: 64 u8 magnitudes and one u64 polarity plane.

The arithmetic contract

Sign is a routing decision. Multiplication is an exact decomposition. Accumulation is a fold.

For each lane pair:

p        = m_a * m_b                  exact, always fits u16
negative = polarity_a XOR polarity_b
acc      = acc - p  if negative, else acc + p

Magnitudes are never negated. The polarity XOR only chooses which side of the fold each product joins. The two candidates are different facade compositions of this same contract: neither is more exact than the other, and they produce the same results.

  • A: U8 × U8 × sign × mul_add. The whole product m_a * m_b is formed in f32 after widening (A' forms it in u16 with mullo), then added to the positive or the negative sum according to the XOR plane.
  • B: U8 × I8 byte-dot. The product is decomposed the way long multiplication (schriftliche Multiplikation) decomposes it:
    • low7 = m_b & 0x7F;
    • top = m_b ^ low7, read as a signed byte, so it is 0 or -128;
    • therefore m_b = low7 - top and m_a * m_b = m_a * low7 - m_a * top;
    • for example, 255 × 255 = 32,385 + 32,640 = 65,025;
    • four dot4_u8_i8_add_masked calls run per block, with the XOR plane as the mask.

No production code changed. The work is examples/u9_head_to_head/{kernels,main}.rs, tests/u9_head_to_head.rs, and the report .claude/knowledge/turbovec9-u9-head-to-head.md.

Result

B is faster in every row, including the symmetric per-block row. Figures are ns per 64 values, data in L1, ranges over 3 runs.

row AVX-512 VNNI AVX-512, no VNNI AVX2
plain u8 × i8 byte-dot 1.89 – 1.94 1.97 – 2.02 2.13 – 2.16
A' end-to-end 7.78 – 7.80 7.77 – 7.81 75 – 82
B end-to-end 3.03 – 3.05 5.67 – 6.22 9.9 – 10.4
A scan 6.95 – 7.14 6.97 – 7.14 70 – 77
B scan 2.69 – 2.77 4.81 – 4.95 9.0 – 9.2

The streamed and arithmetic-only rows are in the report.

A's cost comes from how this composition lowers through the current facade: widening u8 → u16 → f32, and on AVX2, U8x64::mask_blend. It is not a property of U8 × U8 multiplication. Other lowerings of A were not explored. On the AVX-512 builds, the disassembly shows no shuffle, permute, pack, extract or insert in B, in the baselines, or in the flushes. On AVX2 that is not true: LLVM emits 4 vpshufb inside the facade's masked byte-dot (dot4_u8_i8_add_masked), which it uses to spread the bytes of the keep mask. That instruction comes from the facade's own AVX2 code, not from this probe, and was not changed here.

Exactness

Both candidates are bit-exact (no rounding, saturation or wrap) under two conditions:

  • the operands are among the 511 numeric values (never-touched is refused by check, which callers run before the kernel);
  • the running total fits in i64, which holds up to about 2.2 × 10¹² worst-case blocks.

The bounds at each stage:

candidate per-lane bound flush
A 256 × 65,025 = 16,646,400, below 2²⁴ every 256 blocks
B 16,384 × 130,560 = 2,139,095,040, below i32::MAX every 16,384 blocks

Tests, all checked against one independent i64 oracle:

  • all 511 × 511 pairs;
  • full mixed blocks;
  • worst-case runs past both flush bounds, where every byte is 255, so top = -128 and the byte-dot would saturate if it could;
  • never-touched refused in either operand;
  • the split itself for all 256 magnitudes through the kernel's own prepare_b. low7 XOR top gives back the original byte, low7 - top gives back its value, and changing a polarity bit changes only the routing plane, never the bytes.

The tests pass on native, v4, v3, AVX (qemu), v2 (qemu), aarch64 (qemu) and nightly-simd. I broke each of twelve checks on purpose, and every time the tests failed. CI runs this test file only in its x86 test jobs. The other tiers were run locally.

Not proven here:

  • exactness beyond the i64 total;
  • other lowerings of A;
  • CI coverage of every tier;
  • anything about Codebook512 decoding.

Facade gap (recorded, not filled)

The facade has no U8x64 → I8x64 bit view. As a stand-in, bits_as_i8 stores the 64 bytes and loads them back as signed; its cost is inside B's operand preparation. It is not added to the facade because it crosses between u8 and i8.

TurboVec-U9 handoff

The report keeps Arithmetic511 (DR512: 511 values plus the never-touched sentinel) separate from Codebook512 (512 distinct IDs). An exact arithmetic kernel does not make Lloyd-Max512 decoding lossless. #387 measured 329 distinct values after snapping, and the lookup cost is reported.

https://claude.ai/code/session_01XAqKMMjKnig6MXTd41Lf2v


Generated by Claude Code

…U8 x I8 byte-dot

Both candidates read the same block per operand (64 u8 magnitudes, one u64
positive plane) and are written only with ndarray::simd facade words. A keeps
the magnitudes unsigned, routes each product by plane_a ^ plane_b and sums in
f32 (mul_add, or U16x32::mullo then add), exact below 2^24 and flushed every
256 blocks. B splits |b| into its low seven bits and its top bit, signs both
and runs two dot4_u8_i8_add, flushed every 1024 blocks. Scan forms prepare a
query block once and stream index blocks; B's scan form routes the index sign
with dot4_u8_i8_add_masked.

tests/u9_head_to_head.rs checks every candidate against one i64 oracle on all
511 x 511 numeric pairs, full mixed blocks, worst-case runs past both flush
intervals, and refuses the never-touched codeword in either operand.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XAqKMMjKnig6MXTd41Lf2v
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XAqKMMjKnig6MXTd41Lf2v
@coderabbitai

coderabbitai Bot commented Oct 29, 2026 •

Copy link
Copy Markdown
Contributor

Important

  • 🔍 Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

Run configuration
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 6aca4a4d-cda1-4a2a-9806-8192bab74657
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

B no longer negates bytes or narrows through packs. |b| is split with AND and
XOR (low7 = |b| & 0x7F, top = |b| ^ low7, read as signed bytes top is -128),
the sign stays in the presence plane and is flipped with XOR
(plane_a ^ plane_b), and dot4_u8_i8_add_masked applies it as the byte mask:
four masked byte-dots per block, (pos_low7 - pos_top) - (neg_low7 - neg_top).
The symmetric and scan forms now share one accumulator.

The facade has no U8x64 -> I8x64 view, so bits_as_i8 stands in with a store
and a load. Lane totals leave through a stored array read lane by lane, held
apart with black_box so the compiler does not rebuild a permute reduction.
Disassembly of the timed closures: no shuffle, permute, pack, extract or
insert in any B, baseline or flush path; A keeps the widening moves its
u8 -> u16 -> f32 path needs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XAqKMMjKnig6MXTd41Lf2v
B now wins every row of the head-to-head, symmetric included. The report
and the blackboard describe the AND/XOR split, the masked byte-dots, the
shuffle-free flush, the new tables, and the one remaining facade gap.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XAqKMMjKnig6MXTd41Lf2v
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XAqKMMjKnig6MXTd41Lf2v
Both candidates implement one contract: unsigned magnitude product,
polarity XOR as a routing decision, exact bounded fold. B is that product
decomposed like long multiplication. The report now gives the exact domain
and stage bounds, says what is not proven, and drops the claim that A
cannot be written without the widening instructions.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XAqKMMjKnig6MXTd41Lf2v
On an AVX2 build LLVM emits four vpshufb inside the facade's masked
byte-dot to spread the keep mask; the earlier statement was measured on
the AVX-512 build only and read as if it held everywhere.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XAqKMMjKnig6MXTd41Lf2v
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 29, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-29T21:13:16.418830Z 8f66df9 Draft marked ready
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 8f66df9d6e

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread examples/u9_head_to_head/main.rs Resolved
Comment thread examples/u9_head_to_head/main.rs Resolved
The timed loops streamed Vec<Block>, which pads each 72-byte block to 128
bytes because U8x64 is 64-byte aligned. Operands are now two compact arrays
(magnitudes, planes) and each Block is built in registers. The preparation
row passes the whole prepared tuple through black_box, so no lane of low7 or
top can be dropped as unused.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XAqKMMjKnig6MXTd41Lf2v
The streamed rows were inflated by the padded Vec<Block> layout; on compact
72-byte blocks the VNNI B end-to-end row is 6.0-6.5 ns (was 12.9-16.3) and
the B scan 2.75-2.80 (was 5.9-6.9). The preparation row now includes storing
the whole prepared tuple. Verdict unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XAqKMMjKnig6MXTd41Lf2v
The abacus probe streams the same operands and needs the same layout.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XAqKMMjKnig6MXTd41Lf2v
@AdaWorldAPI
AdaWorldAPI merged commit 50fcd54 into master Oct 29, 2026
31 checks passed
AdaWorldAPI added a commit that referenced this pull request Oct 29, 2026
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