Skip to content

MoE: a terminator for the sticky stage marker - #72

Merged
qichao-arlo-wang merged 1 commit into
mainfrom
feat/moe-stage-terminator
Aug 9, 2026
Merged

MoE: a terminator for the sticky stage marker#72
qichao-arlo-wang merged 1 commit into
mainfrom
feat/moe-stage-terminator

Conversation

@qichao-arlo-wang

@qichao-arlo-wang qichao-arlo-wang commented Aug 3, 2026

Copy link
Copy Markdown
Collaborator

Two defects that produce a plausible-looking wrong answer rather than an error.

Not mergeable alone. The emulator holds StageKind equal to MOE_STAGES in both directions, so adding a stage name here fails the companion's guard until it gains the variant. Companion PR to follow; land this one first.

1. The MoE region had no end

Markers are sticky, and a program does not stop where its MoE region does. The last MoE marker therefore ran to the end of the file, and every instruction after it — an lm_head, the next sublayer — was billed to a MoE stage.

Measured on a shared-expert program followed by one ordinary linear_projection:

shared_expert_projection   145  62.8%      <- 87 of these are the epilogue
shared_expert_activation    67  29.0%
other                       19   8.2%
total: 231   ops after the last marker: 87  (37.7%)

That number feeds shared_branch_fraction, which test_branch_split.py calls "the headline claim". It is latent today only because every current testbench program ends at the combine.

Worth stating plainly: this is a hazard the marker mechanism introduced. Under the legacy substring rules the epilogue fell back to other — a conservative miss. Turning markers on converted it into a confident wrong answer.

non_moe joins MOE_STAGES; moe_end_marker() emits it. Separate entry point from moe_stage_marker(MOE_END_STAGE) because closing a region and setting one are different acts.

The name is spelled literally inside MOE_STAGES, not as MOE_END_STAGE. Both repos recover that set with a parser that refuses anything it cannot evaluate, so a Name reference fails to parse rather than resolving — the guard I hardened last round doing exactly its job. A test holds the constant and the entry equal instead.

2. A duplicate VRAM/MRAM name used to succeed

VirtualMemoryManager.allocate had no name registry, unlike FPRAMAllocator. A second allocation under the same name returned a fresh block, the symbol table pointed at it, and the first was leaked — an emitter still holding the old address writes into memory nothing owns. No error.

It now raises. free and reset release the name, so allocate/free/allocate is unaffected.

Verifying this was safe, not assuming it

  1. Instrumented allocate to report duplicate names, ran the shared-expert, router-policy and all six routed-MoE suites → zero duplicates.
  2. Installed the strict version and re-ran those, plus test-aten-{softmax,rms-norm,layer-norm,ffn,flash-attention,rope,embedding-add,linear} and test-large-immediateall pass.
  3. test-aten-bmm fails — and fails identically on unmodified main (emulator exit 101). Pre-existing, not caused here.

This is a change to shared infrastructure inside an otherwise MoE-scoped PR. It is here rather than deferred because documentation alone leaves the silent leak in place, and the leak is the dangerous half.

Also

moe_shared_gate_v0 gained documentation for two limits that were only discoverable by hitting them: name must be unique within a program (the scratch buffers derive from it), and rows is bounded near 830 by FPRAM.

Validation

30 compiler guards pass (test_moe_stage_attribution + test_moe_topk_policy_encoding + the new test_moe_stage_terminator). just test-moe-shared-all passes with 3 bit-exact comparisons; all six routed-MoE suites pass. New guard wired into ci.yml.

🤖 Generated with Claude Code

@qichao-arlo-wang qichao-arlo-wang changed the title MoE: a terminator for the sticky stage marker, and a strict VRAM/MRAM allocator MoE: a terminator for the sticky stage marker Aug 3, 2026

@GeorgeWu1204 GeorgeWu1204 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Markers are sticky, and a program does not stop where its MoE region does. The
last MoE marker therefore ran to the end of the file, and every instruction
after it -- an lm_head, the next sublayer -- was billed to a MoE stage, feeding
the shared-vs-routed ratio the profile exists to report.

This is a hazard the marker mechanism introduced: under the legacy substring
rules the epilogue fell back to `other`, a conservative miss. Turning markers on
converted it into a confident wrong answer.

`non_moe` joins MOE_STAGES and `moe_end_marker()` emits it -- a separate entry
point from `moe_stage_marker(MOE_END_STAGE)` because closing a region and
setting one are different acts, and the caller who has to remember it is
assembling a decoder program, not writing an emitter.

The name is spelled literally inside MOE_STAGES rather than as `MOE_END_STAGE`.
Both repositories recover that set with a parser that refuses anything it cannot
evaluate, so a name reference fails to parse rather than resolving. A test holds
the constant and the entry equal instead.

Also documents two limits on `moe_shared_gate_v0` that were only discoverable by
hitting them: `name` must be unique within a program, and `rows` is bounded near
297 by FPRAM -- `one` and `neg_one` must each be at least `rows` long alongside
the per-token gate scalars, so the ceiling is near `rows * 3`.

Cannot land alone: the emulator holds `StageKind` equal to MOE_STAGES in both
directions, and fails with "compiler emits @stage=non_moe but no StageKind
matches it" until the companion adds the variant.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@qichao-arlo-wang
qichao-arlo-wang force-pushed the feat/moe-stage-terminator branch from 2269bee to 8a6b94b Compare August 9, 2026 12:07
@qichao-arlo-wang
qichao-arlo-wang merged commit d89ad59 into main Aug 9, 2026
4 checks passed
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.

2 participants