## ドキュメント更新 - CURRENT_TASK.md: Phase 25.2完了記録 - phase-25.1b/e/q/25.2 README更新 - json_v0_bridge/README.md新規追加 ## テストファイル整理 - vtable_*テストをtests/archive/に移動(6ファイル) - json_program_loop.rsテスト追加 ## コード整理 - プラグイン(egui/python-compiler)微修正 - benchmarks.rs, instance_v2.rs更新 - MIR関連ファイル微調整 ## 全体成果 Phase 25.2完了により: - LoopSnapshotMergeBox統一管理実装 - ValueId(1283)バグ根本解決 - ~35行コード削減(目標210行の16%) - 11テスト全部PASS、3実行テストケースPASS
6.0 KiB
6.0 KiB
Phase 25.2 — LoopSnapshotMergeBox / Snapshot Merge Unification
Status: completed(LoopSnapshotMergeBox 実装・テスト・代表ケース確認まで完了)
ゴール
- LoopForm v2 / LoopBuilder 周辺に散在していた「continue / break / exit スナップショットのマージ処理」を LoopSnapshotMergeBox という小さな箱に集約し、PHI 入力の構成ロジックを一元化する。
- FuncScannerBox.scan_all_boxes/1 の
ValueId(1283) undefinedなど、 複雑な continue/break を含むループでの SSA バグを構造的に解消する。
実装内容
1. LoopSnapshotMergeBox の導入
- 新規ファイル:
src/mir/phi_core/loop_snapshot_merge.rs - 役割:
- continue_merge 経路用ヘッダ PHI 入力の統合
- exit ブロック用 PHI 入力の統合(header fallthrough + break snapshots + body-local 対応)
- 「全て同じ値なら PHI 不要」といった簡易最適化と、重複 predecessor の正規化
- 主なメソッド:
merge_continue_for_header(preheader_id, preheader_vals, latch_id, latch_vals, continue_snapshots)- preheader / latch / 各 continue スナップショットから、変数ごとのヘッダ PHI 入力
Vec<(bb, val)>を構成。
- preheader / latch / 各 continue スナップショットから、変数ごとのヘッダ PHI 入力
merge_exit(header_id, header_vals, exit_snapshots, body_local_vars)- header fallthrough の値と、各 break スナップショットを統合して exit PHI 入力を構成。
- header に存在しない body-local 変数については break 経路のみから PHI 入力を作る。
optimize_same_value(inputs)- 全て同じ ValueId なら PHI 不要と判断し、その値を返す(単一入力も同様)。
sanitize_inputs(inputs)- 重複する predecessor を最後の値で 1 つに畳み、BasicBlockId 順にソートして安定化。
2. LoopBuilder / LoopFormBuilder からの利用
src/mir/loop_builder.rs- canonical
continue_merge_idを使った後段で、- 以前は LoopBuilder 内で continue スナップショットを手作業でマージしていたが、
- Phase 25.2 では
LoopSnapshotMergeBox::optimize_same_value/sanitize_inputsを利用して continue_merge ブロック上の PHI を構成し、その結果を 1 つのmerged_snapshotとしてseal_phisに渡すように整理。
- canonical
src/mir/phi_core/loopform_builder.rs- exit PHI 構築 (
build_exit_phis) の中で、- header での値(pinned/carriers + body-local で header に存在するもの)と、
- CFG 的に有効な break スナップショットだけをフィルタリングしたリストを用意し、
LoopSnapshotMergeBox::merge_exitで変数ごとのVec<(bb, val)>を構成。- その上で
optimize_same_value/sanitize_inputsを経由して PHI を emit し、必要な場合のみ新しい ValueId を割り当てる。
- exit PHI 構築 (
この結果、continue/exit まわりの「Vec<(bb, val)> 組み立てロジック」は LoopSnapshotMergeBox に集約され、 LoopBuilder / LoopFormBuilder 側は「いつ snapshot を撮るか」「どのブロックが canonical か」に集中できるようになった。
動作確認とバグ修正
1. 代表テストケース
- ループまわりの既存テスト:
mir_stageb_loop_break_continue::*✅mir_loopform_exit_phi::*✅mir_stageb_like_args_length::*✅
- 手書きループの確認:
- 基本ループ:
sum=10(0+1+2+3+4) ✅ - break/continue を含む複雑ループ:
sum=19, i=7✅ - body-local 変数を含むループ:
result=6, i=3(exit PHI で body-local を正しく統合) ✅
- 基本ループ:
2. FuncScannerBox.scan_all_boxes/1 の SSA バグ根治
- 以前の状態:
FuncScannerBox.scan_all_boxes/1内の大きなループで、continue 経路やネストした if/merge を通ったときにValueId(1280)→1318→1299→1283… のように未定義 ValueId が変遷しつつ発生。- これは loop header / exit に向かう PHI 入力が、continue/break スナップショットと header fallthrough の両方を 部分的にしか見ていなかったことに起因していた。
- Phase 25.2 の結果:
- LoopSnapshotMergeBox に continue / exit 経路のスナップショットマージを一元化したことで、
- 13 個の continue を含む複雑なループでも header/exit の PHI 入力が矛盾なく生成されるようになり、
ValueId(1283) undefinedを含む Undefined Value 系のエラーは再現しなくなった。
- LoopSnapshotMergeBox に continue / exit 経路のスナップショットマージを一元化したことで、
規模と効果
- 変更ファイル:
src/mir/phi_core/loop_snapshot_merge.rs(新規)src/mir/loop_builder.rs(continue_merge まわりのスナップショットマージを整理)src/mir/phi_core/loopform_builder.rs(exit PHI 構築を LoopSnapshotMergeBox 経由に変更)
- 行数ベース:
- 追加: 約 500 行(LoopSnapshotMergeBox 本体+11 個のテスト)
- 削除: 約 90 行(LoopBuilder / LoopFormBuilder に散在していた ad‑hoc マージロジック)
- 効果:
- PHI/スナップショットまわりの複雑度が大幅に低下し、今後 Stage‑B / FuncScanner / BreakFinder のループを触る際に、 「どこを見れば continue/break のスナップショット統合ルールが分かるか」が明確になった。
- LoopForm v2 / canonical continue_merge の設計(Phase 25.1e / 25.1q)を、実装レベルで支える小さな箱としての役割を果たしている。
今後への接続
- Phase 25.1e で設計した「LoopScope / IfScope の Env_in/out モデル」と、
Phase 25.1q で導入した canonical
continue_mergeの実装を前提に、 continue/break/exit スナップショットの統合は LoopSnapshotMergeBox に寄せる方針で定着させる。 - これにより、今後 FuncScanner や Stage‑B 側でループ構造を見直す際も、 LoopForm/Region/スナップショット統合の責務を分離したまま小さな差分で進められるようになる。