refactor(interpreter)!: rebuild framework around effect algebra and linker components#671
refactor(interpreter)!: rebuild framework around effect algebra and linker components#671Roger-luo wants to merge 6 commits into
Conversation
Add ToyConcreteInterpreter that can dispatch calls across language stages, so a source-stage function calling a function bodied only at the lowered stage (and vice versa) executes concretely. Expose via run_i64; the CLI Run command now defaults to cross-language, with --per-language opting back into the single-stage run_source_i64 / run_lowered_i64 helpers. The cross-stage call resolution shared with the const-prop fixpoint moves into a new cross_stage module. As a separate cleanup, the test-only profiles, single-run abstract helpers, and directional fixpoint helpers move out of profile.rs / run.rs / fixpoint.rs into src/interpreter/tests/, so the production files contain no #[cfg(test)] items. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…inker components Replace the frame-fusion interpreter with a two-persona design: - Dialect authors implement Interpretable<I> (one generic parameter; Ctx hides env indices/locations) and return a closed Effect algebra (Next/Jump/Branch/Call/Yield/Return/Enter/EnterAny). One impl serves concrete and abstract interpretation; undecidedness lives in the value domain, not the engine. - scf is expressed via Scope/ScopeHook; loop fixpoints are engine-owned, deleting the ScfFrame state machine, Scf*Dispatch traits, and the constprop scf-for location-summary machinery. - Calling conventions are Linker components (SameStageLinker, CrossStageLinker) passed by value; deletes toy-lang's driver clone and makes cross-language execution and analysis a one-line choice. - AbstractInterpreter owns all fixpoints: CFG block worklists with widening, scope re-entry until stable, interprocedural entry/return function summaries. kirin-constprop reduces to the lattice + an alias. - Derives reduce to trait-named macros only: Interpretable, FunctionEntry, InterpDispatch (mirrors ParseDispatch). Frame/StageFrame/Completion/ LiftError/HasLocation derives and forward_through! are removed. - Engine-internal IR queries reuse kirin-ir StageAction dispatch (StageQuery); design doc moved to docs/design/interpreter/. Net -11.7k lines; all 1184 workspace tests pass. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
| let key = (target.stage, target.function); | ||
| self.join_entry(key, target.body, call.args)?; | ||
| if let (Some(info), Some(caller)) = (self.summaries.get_mut(&key), self.current) | ||
| && caller != key |
There was a problem hiding this comment.
Constant propogation is broken on Factorial.
e.g. cargo run -p toy-lang -- run example/toy-lang/programs/factorial.kirin --stage source --function factorial --constprop 5 prints Const(1). On base rust branch, prints Const(120).
Recursive self-calls are excluded from caller dependency tracking. By removing && caller != key, const-prop for factorial 5 now results in Top. A sound result, but less precise than Const(120).
|
@Roger-luo mentioned that the changes in this PR
We still need to rework this more. |
|
I think the conclusion is fable 5 is likely highly hyped and is worse than 5.5 which helped me iterate a few previous set of abstractions... so no free lunch, we gotta simplify the abstraction here ourselves first |
…rame types - Added a new `frame` module to support generalized frame-based traversal in the interpreter. - Introduced `Frame`, `FrameEffect`, and `FrameDriver` traits to facilitate customizable traversal logic. - Implemented `StandardFrame` as the default total frame enum, encapsulating `ScopeFrame` and `CallFrame`. - Enhanced `ConcreteInterpreter` to utilize the new frame system, allowing for more flexible execution. - Updated `AbstractInterpreter` to support customizable policies for summary keying, enabling context-sensitive analyses. - Added `ConstPropContext` for bounded argument tuple context sensitivity in constant propagation analysis.
…ve and WideningStrategy
|
Pushed follow-up commits addressing the frame-generalization and recursive constprop concerns. Summary:
|
… formalism, covering syntax, state model, operational semantics, and type system
- Split frame types into abstract and concrete implementations in the interpreter. - Enhance `If` and `For` structures in the SCF module with additional methods for better access to their components. - Add a new `DataflowLanguage` for testing backward dataflow analyses, integrating various dialects including constants, arithmetic, and control flow. - Update Cargo.toml to include new dependencies and features for the dataflow language. - Implement a custom abstract frame in the toy language tests to observe traversal during analysis.
|
Update after rework: This rework keeps the simplified dialect API, but restore frame traversal customization for compiler authors. Main architectural shape now:
Validation:
|
| @@ -0,0 +1,488 @@ | |||
| //! Backward liveness solver: generic use/def transfer, a CFG worklist with | |||
There was a problem hiding this comment.
I don't think this is using any of our abstract interpretation framework tho? @zhenrongliew
| use kirin_cf::ControlFlow; | ||
| use kirin_function::Return; | ||
| use kirin_ir::{Block, CompileTimeValue, SSAValue}; | ||
| use kirin_scf::{For, If, StructuredControlFlow, Yield}; |
There was a problem hiding this comment.
this is not dialect local
|
I’ve opened a smaller follow-up PR here: #677. That PR supersedes the interpreter-framework refactor in this one since the direction this was taking is not what we want. |
Note
Based on
rust(the Rust workspace lineage). Includes one prior local commit (feat(toy-lang): add cross-language concrete interpreter) that was not yet pushed; the redesign commit supersedes most of it.What
Replaces the frame-fusion interpreter framework with a redesign built around a two-persona contract, deleting ~12.9k lines while adding ~1.2k (net −11.7k). All 1184 workspace tests pass; toy-lang's CLI (
run,run --constprop) works unchanged.Dialect-author surface (
kirin_interpreter::dialect)Interpretable<I: Interp>has one generic parameter (was six:Interpretable<L, I, F, C, E, T>);I::Value/I::Errorare associated types.CtxhidesEnvIndex/Locationplumbing:ctx.read(ssa)/ctx.write(result, value).Effectalgebra:Next/Jump/Branch/Call/Yield/Return/Enter/EnterAny. Undecided control flow is expressed by the value domain (is_truthy()/loop_condition()returningNone), so one impl serves concrete execution and abstract interpretation — kirin-cf drops from two impls to one; the dualConcreteBlockTransfer/AbstractBlockTransfertypes are gone.Scope/ScopeHook: scf.if is twoScope::block(..).bind(..)lines, scf.for is a ~40-line hook. The 830-lineScfFramestate machine and allScf*Dispatchtraits are deleted (scf: 830 → 129 lines).Compiler-author surface (
kirin_interpreter::engine)ConcreteInterpreter<'ir, S, V, E, Lk>(explicit scope stack) andAbstractInterpreter<'ir, S, V, E, Lk>(fixpoint analyzer).Linkercomponents passed by value (SameStageLinkerdefault,CrossStageLinkerfor multi-language pipelines) — never trait impls on engine types, so no more newtype-cloning drivers. toy-lang's 476-lineToyConcreteInterpreterclone is deleted; cross-language execution and cross-language constprop are each one.with_linker(CrossStageLinker)call.Engine-owned fixpoints
AbstractInterpreterowns all three convergence loops: CFG block worklists with widening (cf back-edges), hook-driven scope re-entry with joined entries (scf loops), and interprocedural entry/returnProduct<V>function summaries with caller re-enqueueing. This deletes constprop'sAdvanceableLocationSummary/ScfForConstPropSummaryspecial-casing; kirin-constprop is now the lattice plus a type alias (1281 → 629 lines, almost all value-domain code).Derives
Reduced to trait-named macros only:
Interpretable,FunctionEntry,InterpDispatch(mirrorsParseDispatchon stage enums; single-language pipelines get a blanket impl).Frame,StageFrame,Completion,LiftError,HasLocation, andforward_through!are removed. Engine-internal IR queries reuse kirin-ir's existingStageActiondispatch via the auto-satisfiedStageQuerybundle — no new dispatch machinery beyondInterpDispatch.Why
The previous framework was over-complicated relative to its goals: six-parameter traits, 13 ad-hoc capability/dispatch traits, a viral
TryFrom-lift algebra, per-engine dialect impls, and coherence traps that forced downstream driver clones. This redesign minimizes concepts per persona: a dialect author learnsCtx+Effect+ value-domain bounds (plusScopeHookfor structured dialects); a compiler author learns a derive list, a linker choice, and an engine entry point.Notes for reviewers
docs/design/interpreter/index.md(replacesdocs/design/new-interpreter/);AGENTS.mdinterpreter conventions updated to match.kirin-test-languagesare a good follow-up.kirin-dataflowengine, deliberately not forced throughEffect), context-sensitive call summaries, first-class lambda values, inlineScope::regionbodies in the abstract engine.🤖 Generated with Claude Code