Files
hakorune/docs/development/roadmap/phases/phase-25.1g/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

205 lines
8.8 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.1g — Conservative PHI ↔ ControlForm 統合Rust統合完了
Status: completedControlForm 導線統合+レガシー縮退/挙動は不変)
## ゴール
- 25.1f で整えた **ControlForm 観測レイヤー**LoopShape / IfShape + ControlFormを、
Conservative PHI BoxIf/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 を取り出して、既存の関数に委譲するだけ」の薄いラッパにする。
## 実施内容
### G1: If 用 Conservative PHI への ControlForm 導線(完了)
- 目的:
- `loop_builder.rs::lower_if_in_loop` から `ControlForm::If` を PHI ロジックに渡し、Conservative PHI Box が ControlForm ベースで動けるようにする。
- 実装:
- `src/mir/phi_core/if_phi.rs` に ControlForm ベースの薄いラッパを追加:
```rust
pub fn merge_modified_with_control<O: PhiMergeOps>(
ops: &mut O,
form: &crate::mir::control_form::ControlForm,
pre_if_snapshot: &HashMap<String, ValueId>,
then_map_end: &HashMap<String, ValueId>,
else_map_end_opt: &Option<HashMap<String, ValueId>>,
skip_var: Option<&str>,
then_pred_opt: Option<crate::mir::BasicBlockId>,
else_pred_opt: Option<crate::mir::BasicBlockId>,
) -> Result<(), String> {
use crate::mir::control_form::ControlKind;
let shape = match &form.kind {
ControlKind::If(shape) => shape,
_ => return Ok(()),
};
let merge_bb = shape.merge_block;
let trace = std::env::var("NYASH_IF_TRACE").ok().as_deref() == Some("1");
if trace {
eprintln!(
"[if-phi/control-form] Using ControlForm wrapper: merge={:?} then={:?} else={:?}",
merge_bb, shape.then_block, shape.else_block
);
}
merge_modified_at_merge_with(
ops,
merge_bb,
shape.then_block,
shape.else_block.unwrap_or(shape.then_block),
then_pred_opt,
else_pred_opt,
pre_if_snapshot,
then_map_end,
else_map_end_opt,
skip_var,
)
}
```
- `src/mir/loop_builder.rs::lower_if_in_loop` では、IfShape→ControlForm を構築してこのラッパを直接呼び出すように統合:
```rust
let if_shape = IfShape {
cond_block: pre_branch_bb,
then_block: then_bb,
else_block: Some(else_bb),
merge_block: merge_bb,
};
let form = ControlForm::from_if(if_shape.clone());
crate::mir::phi_core::if_phi::merge_modified_with_control(
&mut ops,
&form,
&pre_if_var_map,
&then_var_map_end,
&else_var_map_end_opt,
None,
Some(then_pred_to_merge),
Some(else_pred_to_merge),
)?;
```
- その後ろで `is_control_form_trace_on()` が true のときに `form.debug_dump()` と `if_shape.debug_validate()` を呼び、
If の形を ControlForm 経由で常時観測できるようにした。
- テスト:
- `cargo test -q mir_stage1_using_resolver_min_fragment_verifies -- --nocapture`
- `cargo test -q mir_stage1_using_resolver_full_collect_entries_verifies -- --nocapture`
- いずれも PASSConservative PHI の挙動変化なし)。
### G2: LoopForm v2 Exit PHI への ControlForm 導線(完了)
- 目的:
- LoopForm v2 Exit PHI が ControlFormLoopShapeを入口に使えるようにする。
- 実装:
- `src/mir/phi_core/loopform_builder.rs` に ControlForm 用ラッパを追加:
```rust
pub fn build_exit_phis_for_control<O: LoopFormOps>(
loopform: &LoopFormBuilder,
ops: &mut O,
form: &crate::mir::control_form::ControlForm,
exit_snapshots: &[(BasicBlockId, HashMap<String, ValueId>)],
branch_source_block: BasicBlockId,
) -> Result<(), String> {
use crate::mir::control_form::ControlKind;
let shape = match &form.kind {
ControlKind::Loop(shape) => shape,
_ => return Ok(()),
};
let exit_id = shape.exit;
let trace = std::env::var("NYASH_LOOPFORM_DEBUG").ok().is_some();
if trace {
eprintln!(
"[loopform/exit-phi/control-form] Using ControlForm wrapper: exit={:?} branch_source={:?}",
exit_id, branch_source_block
);
}
loopform.build_exit_phis(ops, exit_id, branch_source_block, exit_snapshots)
}
```
- `src/mir/loop_builder.rs::build_loop_with_loopform` では、Exit PHI 部分をこのラッパ経由に統一し、
その直後で `ControlForm::Loop` の `debug_dump` / `debug_validate` を行うように整理:
```rust
let loop_shape = LoopShape {
preheader: preheader_id,
header: header_id,
body: body_id,
latch: latch_id,
exit: exit_id,
continue_targets,
break_targets,
};
let form = ControlForm::from_loop(loop_shape.clone());
let exit_snaps = self.exit_snapshots.clone();
crate::mir::phi_core::loopform_builder::build_exit_phis_for_control(
&loopform,
self,
&form,
&exit_snaps,
branch_source_block,
)?;
if is_control_form_trace_on() {
form.debug_dump();
#[cfg(debug_assertions)]
if let Some(ref func) = self.parent_builder.current_function {
loop_shape.debug_validate(func);
}
}
```
- テスト:
- `cargo test -q mir_loopform_exit_phi -- --nocapture`
- `cargo test -q mir_stageb_loop_break_continue -- --nocapture`
- いずれも PASS。Exit PHI の SSA/PHI 挙動は従来と同じで、ControlForm ベースでも構造が崩れていないことを確認。
### G3: ControlForm ↔ Conservative PHI の設計メモ更新(完了)
- 目的:
- 25.1d/e/f/g の成果をまとめ、「If/Loop の PHI が最終的にどのレイヤで SSOT を持つか」を文書で固定する。
- 実施:
- 本 README と `CURRENT_TASK.md` に、Conservative PHI Box と ControlForm レイヤの役割分担を整理して追記。
- 25.1g は「Rust 側での Conservative PHI ↔ ControlForm 統合If/Loop完了」フェーズとして締める。
## このフェーズで残っていること / 先送りしたこと
- `.hako` 側 LoopSSA / StageB パイプラインはまだ ControlFormBox 未統合のまま。
- Test 3StageB MIR verifyの `%0` 問題や、BreakFinderBox 周辺の undefined ValueId は次フェーズLoopSSA 実装側)で扱う。
- LoopBuilder/If 降下そのものを ControlForm ベースに再構成する「Option C」は、Phase 25.2 以降の大きめリファクタとして残しておく。