Assemble G17 fma instructions from scratch, registers included - #23
Merged
Conversation
The register field was the last piece needed to build an instruction rather than edit one. The
index appears twice in the compact form, as byte 0's high nibble and as (r << 1) | 1 in byte 1,
and the two agreed in every instruction examined across three independent fma chains. Confirmed
the only way that counts: redirect an instruction onto another chain's register and predict the
whole kernel's output. Three redirects, three exact matches.
With registers, constants and flags all measured, `encode_fma` assembles the form outright. It
reproduces the compiler's own bytes byte for byte on the cases the compiler emits, which is the
cheapest available check on an assembler -- agree with the only other one in existence -- and
then goes past it. Four forms no Metal compiler produced, each predicted on four inputs before
the bytes were assembled and each exact:
a*3+0.5 87.5, 141.5, 195.5, 303.5
a*1.5-2 0.625, 7.375, 14.125, 27.625
a*7, no addend 1029, 1715, 2401, 3773
-a*2+1 -21, -37, -53, -85
`a*1.5-2` is worth noting: the immediate field is unsigned, so a negative addend is not
representable in it at all and the sign has to travel in the control byte's negate bit. The
encoder does that itself.
One prediction failed first, and it is the reason to write predictions down in advance. A
synthesised `a*7` measured 1536 from x=1 against 1029 predicted -- eight-fold growth per step
where seven was asked for -- because dropping the addend wrote 0x00 into its immediate slot.
Zero there is not inert: it selects a register operand, register 0 happened to be the
accumulator, and the kernel computed a*7 + a. The slot now keeps an ordinary encoded constant
and the control bit alone disables it, which is the configuration the flag scan had verified.
Nothing about that would have been visible from reading the bytes.
The register field also explains an earlier miss. A redirect predicted 976 and measured 980, and
the field was right: chain a had three fmas but only two in the compact form, the one consuming a
freshly loaded value using a longer encoding. The replay now derives the hidden count per chain
and the baseline check is what licenses it -- 488 predicted, 488 measured.
26 ISA tests, 637 in total. The probe re-derives six stages and exits non-zero if any prediction
misses. Lint and vulture clean.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The register field was the last piece needed to build an instruction rather than edit one.
The index appears twice in the compact form — byte 0's high nibble, and
(r << 1) | 1in byte 1 —and the two agreed in every instruction examined across three independent fma chains. Confirmed
the only way that counts: redirect an instruction onto another chain's register and predict the
whole kernel's output. Three redirects, three exact matches.
The assembler
With registers, constants and flags all measured,
encode_fmaassembles the form outright. Itreproduces the compiler's own bytes byte for byte on the cases the compiler emits — the
cheapest available check on an assembler, agreeing with the only other one in existence — and then
goes past it. Four forms no Metal compiler produced, each predicted on four inputs before the
bytes were assembled, each exact:
a*3+0.5a*1.5-2a*7, no addend-a*2+1a*1.5-2is worth noting: the immediate field is unsigned, so a negative addend is notrepresentable in it at all and the sign has to travel in the control byte's negate bit. The encoder
does that itself.
One prediction failed first, which is the point of writing them down in advance
A synthesised
a*7measured 1536 from x=1 against 1029 predicted — eight-fold growth per stepwhere seven was asked for — because dropping the addend wrote
0x00into its immediate slot.Zero there is not inert: it selects a register operand. Register 0 happened to be the
accumulator, so the kernel computed
a*7 + a. The slot now keeps an ordinary encoded constant andthe control bit alone disables it, which is the configuration the flag scan had already verified.
Nothing about that would have been visible from reading the bytes.
The register field also explains an earlier miss. A redirect predicted 976 and measured 980, and
the field was right — chain a had three fmas but only two in the compact form, the one
consuming a freshly loaded value using a longer encoding. The replay now derives the hidden count
per chain, and the baseline check is what licenses that: 488 predicted, 488 measured.
26 ISA tests, 637 in total. The probe re-derives six stages and exits non-zero if any prediction
misses. Lint and vulture clean.
🤖 Generated with Claude Code