Skip to content

Generalize interpreter traversal over CFG, Block, DiGraph, and UnGraph bodies#684

Open
zhenrongliew wants to merge 7 commits into
rustfrom
dl/generalize-body
Open

Generalize interpreter traversal over CFG, Block, DiGraph, and UnGraph bodies#684
zhenrongliew wants to merge 7 commits into
rustfrom
dl/generalize-body

Conversation

@zhenrongliew

Copy link
Copy Markdown
Collaborator

Generalize interpreter body traversal beyond CFGs

Part of #667. This addresses the second follow-up identified in the issue:

Investigate why the interpreter framework is specialized to Region/CFG. It should support bodies such as Block, DiGraph, and UnGraph, demonstrated with a language combining computational graphs and regular SSA IR.

Depends on the Region → CFG rename PR.

Summary

  • Introduces a closed Body vocabulary covering:
    • Cfg
    • Block
    • DiGraph
    • UnGraph
  • Allows callable statements to own CFG, Block, DiGraph, or UnGraph bodies.
  • Separates body representation traversal from invocation context:
    • CfgFrame traverses CFGs.
    • BlockFrame traverses one Block.
    • DiGraphFrame traverses a directed computational graph.
    • CallFrame manages callee resolution, activation lifetime, returns, and caller result binding.
  • Adds a default topological DiGraph walker and reports an error for directed cycles.
  • Provides no universal UnGraph walker. A compiler supplies UnGraph scheduling policy through FrameBuild::from_ungraph_entry; otherwise the interpreter reports NoDefaultWalker.
  • Adds a mixed test language combining ordinary CFG SSA, callable Blocks, directed computational graphs, structured Blocks, and callable UnGraph policy.

Scope

Body remains an intentionally closed enum of Kirin’s built-in body representations. The extensibility point for UnGraph is its traversal policy, since an undirected graph has no inherent execution order.

The remaining toy-lang sparse/dense liveness simplification from #667 is left for a separate PR.

This commit introduces a new test file `body_kinds.rs` that contains acceptance tests for the generic interpreter bodies. The tests cover various scenarios including:
- A Cfg-bodied `main` calling a DiGraph-bodied function.
- A statement inside a Cfg block that owns a DiGraph body.
- A linear callable with a flat instruction list.
- Ensuring that graph nodes run in topological order.

These tests aim to validate the interaction between Cfg-SSA code and DiGraph computational graphs, ensuring correct execution and error handling.
- Renamed `BodyFrame` to `BlockFrame` and adjusted related documentation to reflect the new terminology.
- Enhanced the `ToyFrame` enum to include `BlockFrame` and `CfgFrame`, replacing `BodyFrame`.
- Updated `FrameBuild` implementations in `ToyFrame` and `TracingFrame` to accommodate the new frame types.
- Revised tests in `tests/body_kinds.rs` to ensure compatibility with the updated frame structure.
- Added comprehensive tests for structured control flow (SCF) operations, including `scf.if` and `scf.for`, demonstrating their integration with the new frame types.
- Implemented a custom callable-UnGraph policy to handle ungraph traversal, ensuring proper execution order and output handling.
@zhenrongliew
zhenrongliew requested a review from Roger-luo July 15, 2026 19:22
@zhenrongliew zhenrongliew added area: interpreter Area: issues related to the interpreter. area: Rust Area: issues and pull requests related to Rust code. area: Kirin-rs Area: Rust-version Kirin related components. labels Jul 15, 2026
Base automatically changed from dl/rename-region-to-cfg to rust July 17, 2026 04:11
Resolve conflicts from the Region->CFG rename (#683, now in rust):
- Apply the same Cfg->CFG / CFGs->CFG naming to this branch's changes.
- Keep this branch's restructure of concrete/frames.rs into concrete/frames/
  (drop the stale single-file frames.rs that rust only renamed).
- Drop now-unused CFG imports surfaced by the merge.

All tests (1234) and doctests pass; fmt and clippy clean.
Comment thread crates/kirin-interpreter/src/core/query.rs
zhenrongliew and others added 2 commits July 22, 2026 11:22
Builders set `SSAInfo.kind` (use→def) but nobody ever populated
`SSAInfo.uses` (def→use). Both finalize paths just copied an
always-empty vec through. So finalized IR shipped an empty def-use.

- `StageInfo::rebuild_use_index()`: clears every live value's `uses,`
then scans each live statement's operands (`HasArguments` order) and
records one `Use { stmt, operand_index } `on the value each slot reads.
Idempotent, so the future rewriter can re-run it. Skips deleted
statements/tombstoned SSAs.
- both `finalize()` and `finalize_unchecked()` call it before returning.
- `Use` gains `new()` + `stmt()/operand_index()` accessors, `Copy`, and
serde parity with its container `SSAInfo`.
- `rebuild_use_index` now scan over nodes.digraphs, pushing a
`DiGraphYield { graph, index }` into `SSAInfo.uses`.


```rust
pub enum Use {
    StatementOperand { stmt: Statement, index: usize },
    DiGraphYield     { graph: DiGraph,  index: usize },
}
```

/// The default walk plan of a digraph body (ports, toposorted nodes,
/// yields). Errors on cyclic digraphs.
fn digraph_walk_plan(

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.

a default impl should be an unreachable error

/// Capabilities required by forward frames.
///
/// Re-exported as [`FrameDriver`](crate::FrameDriver).
pub trait ForwardFrameDriver: Env {

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.

I think this trait can be decoupiled more we should revisit it later.

Body::Block(block) => {
F::from_block(BlockFrame::new(target.stage, index, block, entry.args))
}
Body::DiGraph(graph) => {

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.

maybe allow CallFrame to be generic on body frames, so user can specify different body traversal rules with the same call convention.

pub trait HasBodyFrame {
    type CFG;
    type Block;
    ...
}

struct DefaultBodyFrame;

impl HasBodyFrame for DefaultBodyFrame {}

CallFrame<V, DefaultBodyFrame> // the current

}
}

pub fn step_into<I, F>(self, interp: &mut I) -> Result<FrameEffect<F, Completion<V>>, I::Error>

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.

extract a common interface for frames, e.g step_into

Comment on lines +51 to +62
/// Where a graph port sits on its owning statement's boundary.
///
/// This is a **location**, not a value mapping: the owning statement's
/// dialect rule translates port/index into its operands, captures, or
/// results — for values (forward) and demand (backward) alike.
#[derive(Clone, Copy, Debug)]
pub struct PortBoundary {
/// The statement that owns the graph.
pub owner: Statement,
/// Which boundary slot this port occupies.
pub index: usize,
}

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.

Maybe consider moving this to anchor, or somewhere where location belongs.


impl CFGTopology {
/// Deprecated name for [`BodyTopology`]; kept for one release.
pub type CFGTopology = BodyTopology;

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.

we don't need compatibility

@@ -0,0 +1,170 @@
//! Mixed graph/SSA test language: regular SSA IR (arith + cf + function

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.

need a more e2e test, like from a text file to interpreter/abstract interpreter

ScfFor(ScfForFrame<V, E>),
}

impl<V, E> FrameBuild<V, E> for ToyFrame<V, E> {

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.

ultimately this can be derive-ed in most cases, we can revisit this for UX later

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

Labels

area: interpreter Area: issues related to the interpreter. area: Kirin-rs Area: Rust-version Kirin related components. area: Rust Area: issues and pull requests related to Rust code.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants