gqa(adr-0065): D8 — composite returns output handle + output-space DMA

tl.composite now returns the output TensorHandle (not a CompletionHandle) so its result chains like tl.dot's; the handle carries the completion in a CompositeFuture pending so downstream ops and tl.wait auto-await it. out is a handle: out=tl.ref(addr,shape) (HBM, DMA_WRITE inside the composite) or an in-place TCM handle (STORE only); omitted -> TLContext auto-allocates a TCM scratch. out_ptr kept as HBM shorthand (= out=tl.ref(out_ptr, shape)) to avoid churning ~30 existing call sites.

tl.ref now returns space=hbm (it references HBM data; operand-input DMA stays pinned-based per D4 so input streaming is unchanged). tiling: the tile loop's DMA_WRITE is gated on out.space==hbm (out analog of the operand pinned rule) — a TCM output stays on-chip (chainable) and its high-bit scratch address no longer hits the DMA PA decoder.

Fixes the opt2 data-mode crash: the recipe accumulator O is TCM -> no DMA_WRITE -> opt2 now RUNS end-to-end in data mode (enable_data=True). Numeric parity of the recipe MATH ops is the next step. Suite 812 pass / 3 pre-existing fail; existing composite benches use out_ptr->hbm->DMA_WRITE unchanged (byte-equal).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-10 22:29:10 -07:00
parent dd525bfcb7
commit e8d6c283d8
7 changed files with 267 additions and 26 deletions
+6 -2
View File
@@ -175,7 +175,10 @@ def test_tl_composite_nonblocking():
a = tl.load(0x1000, shape=(32, 64), dtype="f16")
b = tl.load(0x2000, shape=(64, 32), dtype="f16")
h = tl.composite(op="gemm", a=a, b=b, out_ptr=0x3000)
assert isinstance(h, CompletionHandle)
# ADR-0065 D8: composite returns the output TensorHandle (chainable),
# carrying the completion in its `pending` field.
assert isinstance(h, TensorHandle)
assert h.addr == 0x3000 and h.space == "hbm"
comp_cmds = [c for c in tl.commands if isinstance(c, CompositeCmd)]
assert len(comp_cmds) == 1
# Flat-ops shape (ADR-0065 D1): head op carries kind + write-back handle.
@@ -195,7 +198,8 @@ def test_tl_wait_specific():
tl.wait(h)
wait_cmds = [c for c in tl.commands if isinstance(c, WaitCmd)]
assert len(wait_cmds) == 1
assert wait_cmds[0].handle == h
# ADR-0065 D8: h is the output handle; tl.wait targets its completion.
assert wait_cmds[0].handle == h.pending.completion
# ── 9. tl.wait() → WaitCmd(handle=None) ──────────────────────────