Skip to content

[Arc] Add LowerCoroutines pass#10596

Open
fabianschuiki wants to merge 1 commit into
mainfrom
fschuiki/lower-coroutines
Open

[Arc] Add LowerCoroutines pass#10596
fabianschuiki wants to merge 1 commit into
mainfrom
fschuiki/lower-coroutines

Conversation

@fabianschuiki
Copy link
Copy Markdown
Contributor

Add an arc-lower-coroutines pass that converts coroutine definitions into plain state machine functions. The lowered functions take an explicit state and program counter as leading arguments, dispatch on the PC to the entry block or one of the resume blocks, and persist all values live across suspension points in a union with one struct variant per resume block.

Each definition is lowered independently: the values live across suspension points are first captured as trailing resume block arguments through a pruned SSA construction based on liveness and iterated dominance frontiers, with constants cloned into their using blocks instead of being persisted. A global sweep then rewrites coroutine calls into regular function calls, lowers the sentinel value ops to constants and comparisons, and replaces all occurrences of the opaque coroutine state and PC types -- including in unrelated ops and nested aggregates -- with the concrete union and integer types. Recursive coroutines are rejected, since their state would require unbounded storage.

Assisted-by: Claude Opus 4.8

Add an `arc-lower-coroutines` pass that converts coroutine definitions
into plain state machine functions. The lowered functions take an
explicit state and program counter as leading arguments, dispatch on
the PC to the entry block or one of the resume blocks, and persist all
values live across suspension points in a union with one struct variant
per resume block.

Each definition is lowered independently: the values live across
suspension points are first captured as trailing resume block
arguments through a pruned SSA construction based on liveness and
iterated dominance frontiers, with constants cloned into their using
blocks instead of being persisted. A global sweep then rewrites
coroutine calls into regular function calls, lowers the sentinel value
ops to constants and comparisons, and replaces all occurrences of the
opaque coroutine state and PC types -- including in unrelated ops and
nested aggregates -- with the concrete union and integer types.
Recursive coroutines are rejected, since their state would require
unbounded storage.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@fabianschuiki fabianschuiki requested a review from maerhart as a code owner June 5, 2026 20:41
@fabianschuiki fabianschuiki added the Arc Involving the `arc` dialect label Jun 5, 2026
@circt-bot
Copy link
Copy Markdown

circt-bot Bot commented Jun 5, 2026

Results of circt-tests run for 5aa4099 compared to results for 6a3a01e: no change to test results.

@fzi-hielscher
Copy link
Copy Markdown
Contributor

I won't be able to do a full review today, just one first thought: Do we want to pass the state to the callee by-value?
I could imagine that the state union may get quite large in practice, even though, for a given suspension point, substantial portions can be unused. So, passing it by-value could lead to a lot of unnecessary copying and pressure on the registers.
On the other hand, I suspect the state SSA value will rarely remain live beyond a call to it's coroutine. So, if we pass it by reference instead, we could reuse the buffer for the new returned state.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Arc Involving the `arc` dialect

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants