Skip to content

feat(rewrite): worklist-based fixpoint driver - #854

Open
alexcgatea wants to merge 7 commits into
rustfrom
alex/queue-based-fixpoint-driver
Open

alexcgatea wants to merge 7 commits into
rustfrom
alex/queue-based-fixpoint-driver

Conversation

@alexcgatea

@alexcgatea alexcgatea commented Nov 10, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

RewriteDriver still runs a fixpoint of sweeps. Each sweep now visits statements from a worklist instead of walking them in place:

  1. The worklist is seeded with every statement under the root, in walk order, as a snapshot taken before any rule runs. The default order is PreOrder.

  2. Statements are popped one at a time, and every rule is tried in order at each, as before.

  3. After each statement, the MutationEvents of its edits add back the statements they may have given a new match. For each statement an event names as changed, replaced or inserted, the sweep adds, top-down:

    • its owner (new Statement::owner)
    • the producers of its operands
    • the statement itself
    • the users of its results

    A statement still in the queue keeps its place, so it is visited once, after the edit. One already visited goes to the back. Only statements under the root are added, so run_at(root) never leaves root's tree.

  4. When the worklist is empty, dead code is cleaned up. The run ends after the first sweep that changes nothing.

Edits the worklist doesn't follow, such as erasures and CFG edits, are picked up by the next sweep, which starts from every statement again. So correctness never depends on the worklist being complete.

Behaviour changes

  • In the driver, erasing the visited statement is allowed in every walk order, including a pattern rule erasing its root, because the driver visits a snapshot rather than walking the IR in place. DriverError::ErasesRoot and DriverError::Walk are removed. Ordinary walks in kirin_ir::walk keep their edit contract: ALLOWS_ERASING_VISITED still decides whether the visited statement may be erased.
  • skip has no effect in the driver, because its walk is a snapshot. Ordinary walks in kirin_ir::walk still honour it.
  • interrupt is unchanged: it ends the current sweep, and the run continues if that sweep changed something.
  • A statement rule's copy may be handed the same statement more than once in a sweep.
  • Block rules run again when their owner is re-added. That happens when an edit changes a statement in one of its blocks.
  • New limit, max_rewrites_per_sweep (default 10,000). A sweep making more rewrites than that fails with DriverError::RewritesExhausted { root, rewrites }. max_sweeps is unchanged.

API

RewriteDriver::new(&rules)                  // PreOrder
    .walk_order::<PostOrder>()              // optional, any WalkOrder
    .max_sweeps(n)
    .max_rewrites_per_sweep(n)
    .run(rewriter)                          // was run::<O>(rewriter)
  • RewriteDriver<'r, L, O: WalkOrder = PreOrder>.
  • kirin-ir gains a public Statement::owner(stage), replacing the walk module's private parent helper.

@alexcgatea
alexcgatea added this pull request to stack #835 November 10, 2026 20:07
Base automatically changed from alex/native-rules to rust November 12, 2026 13:30
alexcgatea and others added 7 commits November 12, 2026 08:31
…isit

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Add Statement::owner, the statement owning a statement's body, replacing
the walk module's private parent helper.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Each sweep seeds a worklist with the statements under the root in a
snapshot walk (PreOrder by default) and adds back the statements a
visit's edits may give a new match. Rules may erase the visited
statement in every order; skip has no effect in the driver. Add a
per-sweep rewrite limit.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@alexcgatea
alexcgatea force-pushed the alex/queue-based-fixpoint-driver branch from 6bbcbe3 to 77d2b50 Compare November 12, 2026 13:32

This branch has not been deployed

No deployments
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.

1 participant