🔧 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)
This commit is contained in:
nyash-codex
2025-11-19 00:02:41 +09:00
parent 263affe379
commit 80f8a7bc8c
17 changed files with 983 additions and 277 deletions

View File

@ -1,6 +1,6 @@
# Phase 25.1g — Conservative PHI ↔ ControlForm 統合(設計+小さな導線
# Phase 25.1g — Conservative PHI ↔ ControlForm 統合(Rust統合完了
Status: planning設計・導線追加既存挙動は変えない
Status: completedControlForm 導線統合+レガシー縮退/挙動は不変
## ゴール
@ -42,77 +42,163 @@ Status: planning設計・導線追加既存挙動は変えない
- Loop 用: `build_exit_phis_for_control(form: &ControlForm, ...)` を追加。
- 最初のステップでは「ControlForm から必要な BlockId を取り出して、既存の関数に委譲するだけ」の薄いラッパにする。
## タスク粒度
## 実施内容
### G1: If 用 Conservative PHI への ControlForm 導線
### G1: 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<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>,
) -> 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 対応が設計どおりかを確認。
- `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;
### G2: LoopForm v2 Exit PHI への ControlForm 導線
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`loopform_builder.rs::build_exit_phis`)にも ControlForm ベースの入口を用意する。
- ステップ:
1. `src/mir/phi_core/loopform_builder.rs` にラッパ関数追加:
```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>)],
) -> 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 誘発系の赤ログが増えていないことを確認。
- 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;
### G3: ControlForm ↔ Conservative PHI の設計メモ更新
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 を持つか」を文書で固定する。
- ステップ:
- `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 の短いサマリを追加して、今どこまで進めたかをいつでも追えるようにする。
- 実施:
- 本 README と `CURRENT_TASK.md` に、Conservative PHI Box と ControlForm レイヤの役割分担を整理して追記。
- 25.1g は「Rust 側での Conservative PHI ↔ ControlForm 統合If/Loop完了」フェーズとして締める。
## このフェーズで「しない」こと
## このフェーズで残っていること / 先送りしたこと
- 既存の Conservative PHI 実装を一気に ControlForm 専用に書き換えること:
- 25.1g は「導線追加+ラッパ」「設計固め」まで
- 実際の置き換えOption B の本体)は、さらに小さなステップに分けて後続フェーズで行う
- LoopBuilder/If 降下の大規模リファクタOption C 相当):
- これは Phase 25.2 以降の仕事として残しておく。
- `.hako` 側 LoopSSA / StageB パイプラインはまだ ControlFormBox 未統合のまま。
- Test 3StageB MIR verifyの `%0` 問題や、BreakFinderBox 周辺の undefined ValueId は次フェーズLoopSSA 実装側)で扱う。
- LoopBuilder/If 降下そのものを ControlForm ベースに再構成する「Option C」は、Phase 25.2 以降の大きめリファクタとして残しておく