Complete Mathematics of "Optimization 6: The AddDot4x1 4-Output Wrapper (via AddDot)"¶
Optimization 6 introduces the named AddDot4x1 kernel — the canonical matvec micro-kernel shape — but constructs it by calling the scalar AddDot four times, once per output row. Like its matmul counterpart (Optimization 6), this is a deliberate correctness-first / structural step: it firmly establishes the 4×1 output kernel contract, which the fused, register-bound versions on either side refine.
Note: Optimization 3 already showed the fused single-loop 4-output form; the ladder here re-covers the territory under the
AddDot4x1name, then Optimization 7 fuses it once more. The naming mirrors the matmul ladder (which also momentarily "regressed" to a dot-product-assembled tile before fusing).
1. The Mathematical Operation¶
The 4×1 kernel produces four output elements from a 4×k panel of \(A\) and the vector \(x\):
In block form, with \(\mathbf{A}\in\mathbb{R}^{4\times k}\) the panel of rows \(i..i+3\):
2. Construction by Four AddDot Calls¶
void AddDot4x1(int k, double *a, int lda, double *x, double *y){
AddDot(k, &A(0,0), lda, x, &y[0]);
AddDot(k, &A(1,0), lda, x, &y[1]);
AddDot(k, &A(2,0), lda, x, &y[2]);
AddDot(k, &A(3,0), lda, x, &y[3]);
}
Each AddDot computes one row dot product (as in Optimization 1):
The four calls iterate over p serially (four separate loops of length \(k\)).
3. Loop Structure¶
The outer matvec loop steps i by 4:
Number of kernel calls: \(m/4\); each performs \(4\) dots of length \(k\), for a total of \(m\) dots and \(2mk\) FLOPs — unchanged.
4. Data Reuse Within the Kernel¶
Per AddDot4x1 call:
- x: read \(4\) times (once per
AddDotcall) — fully reusable, but redundantly re-traversed here; - A row: each row read once per its own
AddDot.
Because the four calls run as separate loops, the same vector x is walked four separate times, and the compiler may not fuse them. This is the reason Optimization 7 re-fuses into one loop: to traverse x exactly once and keep all four accumulators in flight simultaneously.
5. Why the Wrapper Matters Despite the Regression¶
- It gives the kernel a stable name and signature (
AddDot4x1) that organizes the rest of the ladder. - It makes the
4×1output tile the unit of work, matching how the matmul ladder standardizes on4×4. - It is the structural anchor: everything from Optimization 7 onward optimizes inside this
4×1contract.
6. FLOP Accounting¶
Per call: \(4\cdot2k = 8k\) FLOPs; over \(m/4\) calls:
7. Summary¶
| Metric | Optim 5 | Optim 6 (AddDot4x1 via AddDot) |
|---|---|---|
| Kernel name | AddDot1x4 |
AddDot4x1 |
| Outputs per kernel | 4 | 4 |
| Loops per group | 1 (fused) | 4 (serial AddDot) |
| x traversal | once | 4× (redundant) |
| Accumulators in flight | 4 | 1 at a time |
| FLOPs | \(2mk\) | \(2mk\) |
| Purpose | performance | structure / naming |
Optimization 6 defines the 4×1 micro-kernel by assembling four scalar dot products. It may run more slowly than the already-fused Optimization 5, but it establishes the canonical kernel contract that Optimization 7 fuses into a single efficient pass.