Skip to content

feat(io): load a weight in kernel feed order, and have it say so - #1127

Merged
michalharakal merged 1 commit into
developfrom
feature/1120-kernel-feed-order
Aug 25, 2026
Merged

michalharakal merged 1 commit into
developfrom
feature/1120-kernel-feed-order

Conversation

@michalharakal

Copy link
Copy Markdown
Contributor

Closes #1120. Follows #1124 / #1126.

A weight can now be permuted into the order the packed matmul kernels read at load time, and the resulting TensorData declares BlockOrder.INPUT_BLOCK_MAJOR instead of pretending to be canonical.

That is the whole idea: every reader is right about the same bytes. The kernels address them in feed order deliberately; toFloatArray() and view decoding walk the logical grid and fetch each block from where that order put it. Before, feed-order bytes in a type claiming to be canonical decoded to plausible garbage — #1124, and #973/#968 before it.

The payoff

#1096's O(bytes) per-weight relayout stops running at all for such a weight. DefaultCpuOpsJvm relabels the shape over the same array instead.

Asserted structurally, not by timing:

assertSame(payload, (w.data as PackedBlockStorage).packedData, "the weight's own bytes must be untouched")

A relayout would necessarily have produced a different array, so this is the claim rather than a proxy for it.

Two things that had been conflated

shape declares an order?
relayoutPackedWeightForKernels [in, out] no — its shape and its blocks disagree
a loader-produced feed-order weight [out, in] yes, INPUT_BLOCK_MAJOR

The first is a private artifact for the JVM kernels, which address packedData in feed order themselves. #1126 established that it has no honest block order to declare — marking it was the first fix I tried there and it produced zeros. It is left exactly as it was. The second is the new, self-describing thing, and only it flows through views.

Reusing what already existed

The permutation is TensorView.prepack(INPUT_BLOCK_MAJOR), which already owned it — and already emits the conversion on the trace, so #1117 reports the prepack with no new code. A test counts exactly one per weight, and none for a weight kept as stored.

One constraint, stated rather than assumed

KERNEL_FEED requires WeightShapeOrientation.OUT_IN. Which block is "block b of output row o" has no answer while the tensor is still labelled in the file's ne order, so refusing beats permuting against a meaningless grid.

Tests

KernelFeedOrderTest (5): the order is declared and the shape kept; feed-order bytes differ from canonical yet decode to the same matrix — with the difference asserted, so a vacuous fixture cannot pass; the product agrees either way; the permutation happens once and is traced; the OUT_IN constraint refuses.

FeedOrderWeightNoCopyTest (2, commonTest so it runs on native too): the no-copy claim, and a hand-permuted feed-order weight agreeing with the canonical weight it came from.

All fixtures are three blocks per row — at one block per row the two orders coincide and every assertion here would hold vacuously (#968).

#1115's test asserting the old refusal is rewritten, not deleted: it now pins the constraint that remains.

Gate

scripts/pr-gate.sh — all legs passed. An earlier run failed SlicingTest.testPerformanceAccessPatterns on ChromeHeadless — an unrelated dense-slicing test that passes on its own, and the same class of load-sensitive assertion as the one #1107 fixed. Not touched here.

🤖 Generated with Claude Code

Closes #1120. Follows #1124/#1126.

A weight can now be permuted into the order the packed matmul kernels read at
load time, and the resulting TensorData declares BlockOrder.INPUT_BLOCK_MAJOR
rather than pretending to be canonical. Every reader is then right about the
same bytes: the kernels address them in feed order deliberately, while
toFloatArray() and view decoding walk the logical grid and fetch each block
from where that order put it.

The payoff is that #1096's O(bytes) per-weight relayout stops running at all
for such a weight. DefaultCpuOpsJvm relabels the shape over the same array
instead — asserted structurally with assertSame on the byte array, since a
relayout would necessarily produce a different one, and timing proves nothing.

Two things that had been conflated are now separate.
relayoutPackedWeightForKernels still produces bytes labelled [in, out] for the
JVM kernels; that is a private artifact whose shape and blocks disagree, which
is exactly why #1126 found it undecodable and why it keeps no declared order.
A loader-produced feed-order weight is a different thing: it keeps its
[out, in] shape and describes itself.

The permutation reuses TensorView.prepack(INPUT_BLOCK_MAJOR), which already
owned it and already emits the conversion on the trace — so #1117 reports the
prepack without new code, and a test counts exactly one per weight and none
for a weight kept as stored.

KERNEL_FEED requires WeightShapeOrientation.OUT_IN, and says so: which block
is "block b of output row o" has no answer while the tensor is still labelled
in the file's ne order, so refusing beats permuting against a meaningless grid.

#1115's test asserting the old refusal is rewritten rather than deleted — it
now pins the constraint that remains.

Gate: scripts/pr-gate.sh — all legs passed. One earlier run failed
SlicingTest.testPerformanceAccessPatterns on ChromeHeadless, an unrelated
dense-slicing test that passes on its own; not touched here.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

📖 Documentation Preview

The documentation has been built successfully for this PR.

Generated Files:

  • Operator documentation: docs/modules/operators/_generated_/
  • JSON schema output: operators.json

Artifacts:

  • Download the documentation-preview-1127 artifact to view the complete documentation locally.

This comment will be updated automatically when the PR is updated.

@michalharakal
michalharakal merged commit da2bbdc into develop Aug 25, 2026
20 checks passed
@michalharakal
michalharakal deleted the feature/1120-kernel-feed-order branch August 27, 2026 14:48
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.

Packed storage that knows its own block order, so KERNEL_FEED can reach a kernel

1 participant