Repository navigation
Register optimizations for the tagged DFA: reuse per tag, conflict-free tags in their canonical cell - #207
Draft
hhugo wants to merge 3 commits into
Draft
Register optimizations for the tagged DFA: reuse per tag, conflict-free tags in their canonical cell#207hhugo wants to merge 3 commits into
hhugo wants to merge 3 commits into
Conversation
hhugo
force-pushed
the
pr4b-register-optims
branch
from
September 20, 2026 12:24
e41ddf1 to
67d8bc4
Compare
This was referenced Sep 20, 2026
hhugo
force-pushed
the
pr4-tdfa-rewrite
branch
from
September 20, 2026 14:08
a97dd16 to
0d43c9a
Compare
hhugo
force-pushed
the
pr4b-register-optims
branch
from
September 20, 2026 14:08
67d8bc4 to
4ac4e8e
Compare
hhugo
force-pushed
the
pr4-tdfa-rewrite
branch
2 times, most recently
from
September 20, 2026 19:46
d8fef8e to
7c83851
Compare
hhugo
force-pushed
the
pr4b-register-optims
branch
from
September 20, 2026 20:42
4ac4e8e to
3cd2133
Compare
hhugo
force-pushed
the
pr4b-register-optims
branch
from
September 28, 2026 22:15
3cd2133 to
916e3ad
Compare
[Registers] keeps, per logical tag, the pool of working registers allocated so far. [assign_cells] hands a [Pending] write a pooled register that the candidate state does not already hold ([cells_in_use]) and only allocates a fresh one when none is free. Pools of distinct tags stay disjoint, which the collapse of conflict-free tags in the next commit relies on. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
A tag is conflicted when some DFA state holds two distinct registers for it: two live NFA paths recorded different values ([Registers.note_conflicts]). Every other tag only needs one register at a time, so [Registers.collapse_conflict_free] renames its whole pool to its canonical cell and [rename_ops] drops the copies that become no-ops: its writes go straight to the cell the binding code reads, with no final copy. The surviving working registers are compacted above the canonical cells. Two kinds of conflict-free tags still keep a working register, because writing their canonical cell at the wrong time would corrupt a value that is read later: - tags that a transition could set between the mark of one of their rule's accepting states and a later failure, after which the rule's action reads its canonical cells ([note_clobbered]): those set on a transition into a non-accepting state reachable, through non-accepting states, from an accepting state of their rule; - tags that an accepting configuration sets through a delayed write while another configuration of the same state holds them: the final operations write the canonical cell, which would be that other path's register ([final_ops_of]). Collapsing is thus correct without Sedlexing.mark saving the cells. Over test/codegen/test_gen.ml: copies 21 -> 0, cells 42 -> 23. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Codegen tests for the three reasons a tag does not live in its canonical cell: two live starts for one capture (conflicted: two registers, a parallel move on the loop, a copy on accept), a tag recorded again after an accepting state of its rule on the way to a possible failure, and a tag that an accepting path sets while another path holds it. A behaviour test pins the sub-matches of the last shape. The Current/Goal notes of the optimization-tracking tests go back to one cell per tag. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
hhugo
force-pushed
the
pr4b-register-optims
branch
from
September 28, 2026 22:21
916e3ad to
895cb11
Compare
This was referenced Sep 30, 2026
This branch has not been deployed
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.
Register optimizations for the tagged DFA. Stacked on #209 (base: the
pr4d-tdfa1branch), three commits. Pure optimization: every captured value intest/basic.mlis unchanged; generated code and cell counts change.After #204 every tag write gets a fresh working register and every accepting state copies the accepting path's registers into the canonical cells read by the bindings: two cells per tag and a copy per tag on accept. This PR brings ordinary patterns back to one cell per tag and no copy. Over
test/codegen/test_gen.ml: copies 21 → 0, cells 42 → 23; realistic lexer: copies 2 → 0, cells 4 → 2.Commits
Reuse working registers per logical tag. A new write takes a register the tag already used that the candidate state does not hold, else a fresh one. Registers are never shared between tags.
Write conflict-free tags directly to their canonical cell. A tag is conflicted when some state holds two registers for it. The registers of every other tag are renamed into its canonical cell once all states are built, and the copies that become no-ops are dropped. Two kinds of conflict-free tags still keep a working register, because writing their canonical cell at the wrong time would corrupt a value read later:
So collapsing does not rely on
Sedlexing.marksaving the cells (Stop copying the capture cells in Sedlexing.mark and backtrack #208).Tests: a codegen test for each of the three reasons a tag keeps working registers, a behaviour test for the last one, and the Current/Goal notes back to one cell per tag.
Verification
The #202 oracle, run locally with the TDFA(1) interpreter and no cell snapshot: no disagreement on the hand-written cases nor on 5M random cases. With either of the two conditions of commit 2 disabled, the same sweep finds wrong captures.
🤖 Generated with Claude Code