M7d: symmetry storage halving — ceil(L/2) stored rows, mirrored dots - #10
Merged
Conversation
Lever 3 of the optimization campaign (PLAN section 7), the RatioTap half
of the two-PR lever (DspTap grew dot_row_reversed first; this bumps the
pin to c2bfbdb and consumes it).
The linear-phase prototype gives b_p[t] = b_{L-1-p}[T-1-t]: branch p is
branch L-1-p tap-reversed. The table now stores only ceil(L/2) rows (74
of 147 down, 80 of 160 up) and a mirrored phase dots its partner's
stored row backward via tap::dsp::dot_row_reversed — same products, same
accumulation order, bit-identical outputs. Quantization is canonical
over the stored half, so the mirror is exact by construction and the
fixed-point exact-unity row sums carry over (reversal preserves the
multiset). Storage, pinned by test: economy f32 44.8 -> 22.5 KiB (down),
27.5 -> 13.8 KiB (up); transparent 105.7 -> 53.2 / 60.0 -> 30.0 KiB;
Q15 halves those again.
Compute cost: ZERO baseline changes on all three targets — with one
codegen subtlety the ratchet caught and the diagnostics isolated:
inlining both dot arms in the walk broke Arm's unrolled forward codegen
(M55 up_q15 +3.3%, reversed kernel itself measured free), while
outlining the mirrored arm broke Hexagon's (down_q31 +3.3% called, +2.7%
inlined). The mirrored-arm out-lining is therefore gated per target
(TAP_RATIO_MIRRORED_DOT_ATTR), the same measured-per-target pattern as
the tap::dsp kernel gates. Worst residual rides inside the two-sided
gate (Hexagon down_q31 +2.7%); Arm came out slightly ahead (M33 Q31
-2.5%, M55 up_q15 -1.1%).
Verification: 58/58 host (gcc + clang -Werror); M55 and M33 bare-metal
suites green — the M33 leg is the on-target bit-exactness proof of the
SMLALDX swapped-lane pairing (impulse-reproduces-table sweeps every
mirrored phase with the intrinsic active); Hexagon 56/56; every-phase
table battery extended with the exhaustive mirror-identity sweep;
bluetooth_bridge identical; clang-tidy clean.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ldeq57sBySx2nFTQsGcQB6
The DspTap merge rewrote the branch commit (c2bfbdb -> dfbe18d, identical tree); the pin must be reachable from dsptap main or recursive submodule checkouts break once the branch ref is pruned. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Ldeq57sBySx2nFTQsGcQB6
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.
This PR bumps the DspTap submodule pin to the
dot_row_reversedcommit — merge DspTap #6 first so the pinned commit is reachable from its main.What
Lever 3 of the M7 campaign, in two PRs per the substrate discipline (kernel in DspTap first, consumer here).
The linear-phase prototype satisfies
b_p[t] = b_{L−1−p}[T−1−t]— branchpis branchL−1−ptap-reversed. So:basic_phase_tablenow stores only ⌈L/2⌉ rows (74 of 147 down, 80 of 160 up; odd L keeps its self-symmetric middle branch as a stored row). A mirrored phase dots its partner's stored row backward viatap::dsp::dot_row_reversed— same products, same accumulation order, bit-identical outputs to a full table.stored_row/is_mirroredpairing the hot path uses, plus an exhaustive mirror-identity sweep (every phase × every tap).The part the ratchet earned
First measurement: M55 up_q15 +3.3% REGRESSION. Diagnostics isolated it — a build with both arms calling the forward kernel cost the same, so the reversed kernel is free and the second inlined dot expansion in the walk's loop body is what broke Arm's unrolled codegen. Outlining the mirrored arm fixed Arm — and regressed Hexagon (down_q31 +3.3% called vs +2.7% inlined: hexagon-clang keeps both expansions tight and pays for the call instead). So the mirrored-arm out-lining is gated per target (
TAP_RATIO_MIRRORED_DOT_ATTR), the same measured-per-target pattern as thetap::dspkernel gates.Final result: zero baseline changes on all three targets — the halving is compute-free within the ±3% gate. Worst residual: Hexagon down_q31 +2.7% (rides as slack); Arm came out slightly ahead (M33 Q31 −2.5%, M55 up_q15 −1.1%).
Verification
-Werror); scipy vectors, pull-parity, custom-taps impulse all bit-exact.bluetooth_bridgeidentical; clang-tidy clean.🤖 Generated with Claude Code
https://claude.ai/code/session_01Ldeq57sBySx2nFTQsGcQB6
Generated by Claude Code