# Phase 25.1g — Conservative PHI ↔ ControlForm 統合(設計+小さな導線) Status: planning(設計・導線追加/既存挙動は変えない) ## ゴール - 25.1f で整えた **ControlForm 観測レイヤー**(LoopShape / IfShape + ControlForm)を、 Conservative PHI Box(If/Loop 用 SSA/PHI ロジック)の入口として使えるようにする。 - いきなりすべてを書き換えるのではなく、 1. If 用 Conservative PHI → ControlForm 対応 2. LoopForm v2 Exit PHI → ControlForm 対応 の順に、小さく段階的に寄せる。 - 各ステップごとに Rust テストと `tools/test_stageb_min.sh` を流しつつ、 SSA/PHI の赤ログが増えていないことを確認して進む。 ## 前提(25.1f までで揃ったもの) - Rust: - `src/mir/control_form.rs`: - `LoopShape` / `IfShape` / `ControlKind` / `ControlForm` / `CfgLike` / `is_control_form_trace_on()` が定義済み。 - `src/mir/loop_builder.rs`: - LoopForm v2 経路(`build_loop_with_loopform`)の出口で `LoopShape` → `ControlForm::Loop` を生成・トレース。 - `lower_if_in_loop` の merge 部分で `IfShape` → `ControlForm::If` を生成・トレース。 - `NYASH_CONTROL_FORM_TRACE`(未設定=ON, 0/false=OFF)でトレース ON/OFF 切り替え可能。 - Conservative PHI: - If 用: `src/mir/builder/phi.rs` / `src/mir/phi_core/if_phi.rs`(Conservative PHI Box 実装)。 - Loop 用: `src/mir/phi_core/loopform_builder.rs`(LoopForm v2 の Exit PHI / Carrier/Pinned 対応)。 - .hako: - `lang/src/shared/mir/control_form_box.hako`: - `static box ControlFormBox`(kind_name + loop_* / if_* + entry/exits)だけ実装済み(まだ未使用)。 ## 方針(Option B の範囲) - **このフェーズでは**: - Conservative PHI の「インターフェースと呼び出し位置」に ControlForm の導線を用意する。 - ただし既存のロジック(引数で BlockId を受け取る形)は残し、ControlForm 導線は **観測+補助的な入口** として扱う。 - 影響範囲は If / Loop の PHI 部分に限定し、他の MIR 降下には触れない。 - 実装方針: - 新しい API を「足す」→ 既存コードから段階的に使い始める、という形で進める。 - 例: - If 用: `merge_modified_at_merge_with_control(form: &ControlForm, ...)` を追加。 - Loop 用: `build_exit_phis_for_control(form: &ControlForm, ...)` を追加。 - 最初のステップでは「ControlForm から必要な BlockId を取り出して、既存の関数に委譲するだけ」の薄いラッパにする。 ## タスク粒度 ### G‑1: If 用 Conservative PHI への ControlForm 導線 - 目的: - `loop_builder.rs::lower_if_in_loop` から、`ControlForm::If` を PHI ロジックに渡せるようにする。 - ステップ: 1. `src/mir/phi_core/if_phi.rs` に薄いラッパ関数を追加: ```rust pub fn merge_modified_with_control( ops: &mut O, form: &crate::mir::control_form::ControlForm, pre_if_snapshot: &HashMap, then_map_end: &HashMap, else_map_end_opt: &Option>, skip_var: Option<&str>, ) -> Result<(), String> { // ControlForm::If から cond/then/else/merge を取り出し、 // 既存の merge_modified_at_merge_with に橋渡しするだけ(ロジックは変えない)。 } ``` 2. `lower_if_in_loop` 側で: - 既存の `merge_modified_at_merge_with` 呼び出しの直前/直後にコメントを付け、 - 将来的に `merge_modified_with_control` に置き換えられるように位置を明示する(25.1g ではまだ呼び替えない or dev フラグで限定)。 3. テスト: - `cargo test -q mir_stage1_using_resolver_min_fragment_verifies -- --nocapture` - `cargo test -q mir_stage1_using_resolver_full_collect_entries_verifies -- --nocapture` - 必要なら `NYASH_CONTROL_FORM_TRACE=1` で IfShape ログを確認し、BlockId 対応が設計どおりかを確認。 ### G‑2: LoopForm v2 Exit PHI への ControlForm 導線 - 目的: - LoopForm v2 Exit PHI(`loopform_builder.rs::build_exit_phis`)にも ControlForm ベースの入口を用意する。 - ステップ: 1. `src/mir/phi_core/loopform_builder.rs` にラッパ関数追加: ```rust pub fn build_exit_phis_for_control( loopform: &LoopFormBuilder, ops: &mut O, form: &crate::mir::control_form::ControlForm, exit_snapshots: &[(BasicBlockId, HashMap)], ) -> Result<(), String> { // form.kind が Loop の場合に限り、 // shape.preheader/header/body/latch/exit から exit_id/branch_source_block を決めて // 既存の build_exit_phis に委譲するだけ。 } ``` 2. `LoopBuilder::build_loop_with_loopform` からは: - 現在どおり `loopform.build_exit_phis(self, exit_id, branch_source_block, &exit_snaps)` を呼び続ける。 - コメントで「ControlForm 経由の入口」があることを明示し、将来の切り替えポイントを固定する。 3. テスト: - `cargo test -q mir_loopform_exit_phi -- --nocapture` - `cargo test -q mir_stageb_loop_break_continue -- --nocapture` - `./tools/test_stageb_min.sh` を流して、Exit PHI 誘発系の赤ログが増えていないことを確認。 ### G‑3: ControlForm ↔ Conservative PHI の設計メモ更新 - 目的: - 25.1d/e/f/g の成果をまとめ、「If/Loop の PHI が最終的にどのレイヤで SSOT を持つか」を文書で固定する。 - ステップ: - `phase-25.1d/README.md` と `phase-25.1f/README.md` をリンクしつつ、 - Conservative PHI Box の責務(If/Loop 両方) - ControlForm レイヤの責務 - .hako 側 `ControlFormBox` / `LoopSSA` の予定 を Phase 25 全体の流れの中に整理して追記する。 - `CURRENT_TASK.md` に 25.1g の短いサマリを追加して、今どこまで進めたかをいつでも追えるようにする。 ## このフェーズで「しない」こと - 既存の Conservative PHI 実装を一気に ControlForm 専用に書き換えること: - 25.1g は「導線追加+ラッパ」「設計固め」まで。 - 実際の置き換え(Option B の本体)は、さらに小さなステップに分けて後続フェーズで行う。 - LoopBuilder/If 降下の大規模リファクタ(Option C 相当): - これは Phase 25.2 以降の仕事として残しておく。