Files
hakorune/docs/development/roadmap/phases/phase-25.1j/README.md
nyash-codex 80f8a7bc8c 🔧 Hotfix 7 (Enhanced): ValueId receiver alias tracking for nested loops
- Problem: Pinned receiver variables in loops cause undefined ValueId errors
- Enhanced fix: Update all receiver aliases (me + all __pin$N$@recv levels)
- Handles nested loops by updating previous pin levels
- Test status: Partial improvement, ValueId(50) → ValueId(40)
- Further investigation needed for complete fix

Files modified:
- src/mir/phi_core/loopform_builder.rs (emit_header_phis)
2025-11-19 00:02:41 +09:00

126 lines
9.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Phase 25.1j — LoopSSA v2 本体 & StageB harness 強化
Status: planning.hako 側 LoopSSA v2 本体Rust SSA/PHI は触らない)
## ゴール
- 25.1i で整えた **LoopSSA + ControlFormBox 観測レイヤー** の上に、.hako 側 LoopSSA v2 の「本体」を載せる準備をする。
- 特に StageB minimal harness`tools/test_stageb_min.sh`Test 2 で出ている
`MIR compilation error: Undefined variable: trace` を構造的に解消する。
- 文字列ハードコードベースの Exit PHI 注入(`_collect_phi_vars` / synthetic `"r{block}_{var}"`)は **即座には捨てず**
将来の v2 実装に移行しやすいよう責務を整理する。
- このフェーズでは:
- LoopSSA / BreakFinderBox / PhiInjectorBox の **trace 変数の扱い**とスコープを整理し、
「どこで ENV を読むか」「どこまで Box 内のローカルで閉じるか」を決める。
- StageB Test 2 が Program(JSON v0) 出力まで進み、Rust 側 MirBuilder の SSA/PHI 検証に到達できる状態を作る。
- StageB Test 3 の `%0`/SSA 問題については「LoopSSA v2 が悪化させていない」ことの確認まで(根治は次フェーズ)。
## 前提25.1i までで揃っているもの)
- Rust:
- Loop/If:
- LoopForm v2 + Conservative PHI Box が ControlForm`LoopShape`/`IfShape`)経由で統合済み。
- レガシー `build_loop_legacy` は削除済みで、LoopForm v2 が唯一のループ構築経路。
- テスト:
- `mir_loopform_exit_phi` / `mir_stage1_using_resolver_*` / `mir_stageb_loop_break_continue` は緑。
- `.hako`:
- `lang/src/compiler/builder/ssa/loopssa.hako`:
- `LoopSSA.stabilize_merges(stage1_json)``BreakFinderBox.find_breaks``PhiInjectorBox.inject_exit_phis` の簡易パイプライン。
- `HAKO_LOOPSSA_EXIT_PHI` で Exit PHI 注入の ON/OFF を制御している。
- `lang/src/compiler/builder/ssa/exit_phi/break_finder.hako`:
- 文字列ベースで `"loop_header":` / `"loop_exit":` を探す `_find_loops`
- `header_id < id < exit_id` の範囲で body block を推定する `_find_loop_body`
- break を「`jump` terminator の `target``exit_id`」な block として検出。
- `HAKO_COMPILER_BUILDER_TRACE=1``[break-finder] …``[loopssa/control] …` ログを出す。
- `lang/src/shared/mir/control_form_box.hako`:
- 現行構文で `ControlFormBox` を定義(`kind_name` / `entry` / `exits` + loop/if 用フィールド)。
- `from_loop(header_id, exit_id, body_blocks)` / `from_if(cond, then, else, merge)` で Loop/If の形を復元。
- `lang/src/compiler/entry/compiler_stageb.hako`:
- StageB entry が `CompilerBuilder.apply_all(ast_json)` を通した後の JSON を出力する構成。
- 25.1i で `using lang.compiler.parser.parser_box as ParserBox` 等の修正により parse error は解消済み。
- StageB minimal harness:
- `tools/test_stageb_min.sh`:
- Test1: 直接 VM 実行 → RC=0。
- Test2: StageB 経由 → LoopSSA/Exit PHI 経路まで進むが最終的に
`MIR compilation error: Undefined variable: trace` で停止LoopSSA v2 経路における trace スコープの問題)。
- Test3: `NYASH_VM_VERIFY_MIR=1``%0` undefined 由来の SSA 問題が残っている(根本は LoopSSA だけとは限らない)。
## 方針25.1j: LoopSSA v2 本体の入口を整える)
### JA: LoopSSA/BREAK/PHI 周辺の trace 変数スコープの整理
- 目的:
- `.hako` 側 LoopSSA パスの中で `trace` という名前が **常にローカル or Box フィールドとして定義されている** 状態にする。
- StageB Test2 における `Undefined variable: trace` を根治し、Program(JSON v0) 出力まで進める。
- 方針:
- 「ENV から読む責務」と「boolean フラグを渡して使う責務」を分離する。
- 具体的には:
- `LoopSSA.stabilize_merges` の先頭で `local builder_trace = env.get("HAKO_COMPILER_BUILDER_TRACE")` を読む。
- `BreakFinderBox.find_breaks` / `PhiInjectorBox.inject_exit_phis` には **数値フラグ `trace_flag`** を第3引数として渡す0/1
- 各 Box 内では `local trace = trace_flag`(または `me.trace` フィールド)として閉じた名前にする。
- 既存の `local trace = env.get("HAKO_COMPILER_BUILDER_TRACE")` は LoopSSA に集約し、下位 Box は「引数でもらったフラグだけを見る」構造に変える。
### JB: LoopSSA v2 の責務再定義(設計)
- 目的:
- `LoopSSA.stabilize_merges` が「何を受け取り、どこまで責任を持つか」を Rust LoopForm v2 に揃えた形で **明文化** する。
- StageB / LoopSSA / BreakFinderBox / PhiInjectorBox の責務分割を Box 単位で固定し、将来の v2 実装時も迷わない足場を作る。
- 方針:
- LoopSSA パスを 3 層に分解して設計を書く:
1. **LoopSSAオーケストレータ箱**
- input: Stage1 Program(JSON v0)(単一関数 or Program 全体)。
- output: Loop break に対する exit PHI が挿入された Program(JSON v0)。
- 責務:
- dev トレースフラグ(`HAKO_COMPILER_BUILDER_TRACE`)と機能フラグ(`HAKO_LOOPSSA_EXIT_PHI`)を解釈。
- `BreakFinderBox.find_breaks(stage1_json, trace_flag)` を呼んで Loop + break 情報を収集。
- `PhiInjectorBox.inject_exit_phis(stage1_json, breaks, trace_flag)` に処理を委譲。
- 例外時は JSON を変更せず FailFast する(「部分的に壊れた JSON を返さない」)。
2. **BreakFinderBox解析箱 / readonly**
- input: Stage1 Program(JSON v0)、trace_flag。
- output: break 情報の配列(`[{block_id, exit_id, loop_header}, …]`)。
- 責務:
- `"loop_header":NNN` / `"loop_exit":MMM` のペアを見つけ、単純な LoopScope を構成する。
- ControlFormBox に Loop 形header/exit/bodyを写し取る観測用
- JSON 文字列は一切書き換えない(解析専用)。
3. **PhiInjectorBox変換箱 / writeonly**
- input: Stage1 Program(JSON v0)、break 情報配列、trace_flag。
- output: Exit PHI 相当の命令を instructions 配列の先頭に挿入した Program(JSON v0)。
- 責務:
- break ごとの incoming 値を集約し、`phi_vars = [{name, incoming:[{block,value},…]}, …]` を構成。
- Exit block の `"instructions":[ … ]` の直後に PHI 相当 JSON をテキスト挿入する。
- 既存の命令配列順を壊さないPHI は「先頭に」挿入するのみ)。
- Carrier / Pinned / Invariant の扱いは **設計としてだけ** 固める:
- Carrier: ループ内で値が更新され、exit でも必要になる変数Rust 側 Carrier と対応)。
- Pinned: pin 付き一時値(`__pin$…`)など、観測目的で特別扱いする変数。
- Invariant: ループ外で定義され、ループ内で再定義されない値PHI 不要)。
- 25.1j では **Exit PHI のアルゴリズム自体はまだ現行の simple 版のまま** としつつ、
LoopSSA / BreakFinderBox / PhiInjectorBox の責務境界だけを README とソースコードコメントで明確にする。
### JC: BreakFinder v2 への足場ControlFormBox の本格利用準備)
- 目的:
- 既存の `loop_info = {header, exit, body}` ベースに加えて、ControlFormBox に Loop 形を必ず写す。
- 方針:
- `BreakFinderBox._find_loops` 内で:
- `loop_info` 生成に加えて `local cf = new ControlFormBox()``cf.from_loop(header_id, exit_id, body_blocks)` を常時呼ぶ。
- trace ON のとき `[loopssa/control]` ログに加えて ControlFormBox の内容も JSON 風にまとめて出すheader/exit/body_size
- このフェーズでは戻り値の構造はまだ変えず、`find_breaks` は従来どおり breaks 配列を返す。
### JD: PhiInjector v2 設計(実装は次フェーズ)
- 目的:
- Exit PHI 注入を ControlFormBox/LoopScope ベースで書き直すための **設計を先に固める**
- 方針:
- 25.1j ではコード本体は変えず、`phi_injector.hako` と README に設計のみ追記:
- `inject_exit_phis(json_str, breaks, trace_flag)` の将来形ControlFormBox + break 群 + JSON v0を定義。
- Carrier/Pinned/Invariants を Rust LoopForm v2 の概念に揃える。
- `common_vars = ["i","n","item",…]` のハードコードは「v2 で撤退予定」とコメントで明示。
- 実アルゴリズムの書き換えv2 本体)は Phase 25.1k 以降の大きなタスクとして分離する。
## このフェーズで「しない」こと
- `.hako` 側 LoopSSA を Rust LoopForm v2 と完全同型にすることPHI アルゴリズムの全面移植)は行わない。
- StageB Test3 の `%0`/SSA エラーを「必ずゼロにする」こと:
- 25.1j では **trace 変数のスコープ修正と LoopSSA v2 の責務整理** に集中する。
- `%0` の根治は、LoopSSA v2 本体Carrier/Pinned/Exit PHIを実装する次フェーズのターゲットとする。