42 lines
2.7 KiB
Markdown
42 lines
2.7 KiB
Markdown
|
|
Phi Entry in Hako — Design Notes (SSA/CFG Parity)
|
|||
|
|
|
|||
|
|
Purpose
|
|||
|
|
- Specify how to implement SSA φ (phi) on the Hakorune side cleanly, mirroring Rust/Core invariants while keeping the code small and testable.
|
|||
|
|
|
|||
|
|
Rust/Core invariants to adopt (parity)
|
|||
|
|
- Placement: φ nodes are considered at the head of a block (grouped), applied once at block entry.
|
|||
|
|
- Selection: choose one incoming (value, pred) where pred == prev_bb (the block we arrived from).
|
|||
|
|
- Coverage: incoming pairs cover all reachable predecessors. Missing entries are a hard error in strict mode.
|
|||
|
|
- Execution: after φ application, the resulting dst registers are defined before any instruction in the block reads them.
|
|||
|
|
|
|||
|
|
Hako design (Reader → IR → Runner)
|
|||
|
|
- Reader (JsonV1ReaderBox, extended):
|
|||
|
|
- Parse MIR JSON v1 into a minimal per-function IR: blocks (id, insts[]), and extract φ entries into a phi_table (block_id → [(dst, [(pred,val)])]).
|
|||
|
|
- Keep scanning light by using JsonFragBox helpers (read_int_from/after, seek_array_end, scan_string_end).
|
|||
|
|
- PhiTable (V1PhiTableBox):
|
|||
|
|
- API: apply_at_entry(regs, phi_table, prev_bb, block_id, policy) → writes dst from the matched incoming.
|
|||
|
|
- policy.strict (default ON): fail-fast when incoming is missing or source is undefined; policy.tolerate_void (dev) treats missing/undefined as Void/0.
|
|||
|
|
- Runner (NyVmDispatcherV1Box):
|
|||
|
|
- On block entry: apply φ via PhiTable; then run instructions (φ removed from the runtime loop).
|
|||
|
|
- Branch/jump update prev_bb and bb; compare/branch read the compare.dst as the condition value.
|
|||
|
|
|
|||
|
|
Flags
|
|||
|
|
- HAKO_V1_PHI_STRICT=1 (default), HAKO_V1_PHI_TOLERATE_VOID=0 (dev-only safety).
|
|||
|
|
- HAKO_V1_DISPATCHER_FLOW=1 to run the IR-based flow; keep fallback to Mini-VM and Core for stability during bring-up.
|
|||
|
|
|
|||
|
|
Testing plan
|
|||
|
|
- Canary 1: simple if (then/else with single incoming) → ret of φ.dst equals the selected value.
|
|||
|
|
- Canary 2: multi-incoming with (pred,val) pairs for both paths; ensure prev_bb select works for both branches.
|
|||
|
|
- Canary 3: nested branch (entry φ in deeper block).
|
|||
|
|
- Negative: missing incoming for reachable pred → strict fail; tolerate_void → rc stable with Void/0.
|
|||
|
|
|
|||
|
|
Why this works in Hako
|
|||
|
|
- Although Hako doesn’t have first-class structs, the minimal IR and phi_table can be represented as arrays of tuples or MiniMap-backed strings with helper boxes.
|
|||
|
|
- JsonFragBox provides escape-aware scanning; Reader avoids brittle substring logic.
|
|||
|
|
- Runner remains small and composable: “read/apply/run” with φ isolated at entry.
|
|||
|
|
|
|||
|
|
Migration plan
|
|||
|
|
- Phase 20.37: introduce Reader+PhiTable+entry-apply (flagged), keep fallback to Mini-VM/Core.
|
|||
|
|
- Phase 20.38+: expand coverage (binop/compare edges), flip v1 verify default to Hako when parity canaries are green.
|
|||
|
|
|