refactor(phi): Phase 26-B-3 - loopform_builder.rsでPhiInputCollector統合完了

loopform_builder.rsでPhiInputCollector使用に移行

# 変更内容
- PhiInputCollectorのuse文追加
- seal_phis() pinned変数: PhiInputCollector使用に変更
- seal_phis() carrier変数: PhiInputCollector使用に変更
- build_exit_phis(): PhiInputCollector使用に変更
- sanitize_phi_inputs()関数削除(PhiInputCollectorに置き換え)
- test_sanitize_phi_inputs()削除(PhiInputCollectorテストで代替)

# コード削減
- 8行削減(51削除、43追加)
- sanitize_phi_inputs()関数: 14行削除
- test_sanitize_phi_inputs(): 13行削除
- PhiInputCollector使用コード: 19行追加

# 改善効果
1. 重複排除: sanitize処理を統一
2. 決定性向上: BTreeMap使用(HashMapから移行)
3. テストカバレッジ: PhiInputCollectorに包括的テスト

# テスト結果
 7/7 loopformテスト全PASS
 既存機能完全互換

# 次のステップ
Phase 26-B-3続行: loop_snapshot_merge.rsでの統合

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
nyash-codex
2025-11-20 17:55:23 +09:00
parent 54f6ce844b
commit 059533876e

View File

@ -10,6 +10,7 @@
use crate::mir::{BasicBlockId, ValueId};
use crate::mir::phi_core::loop_snapshot_merge::LoopSnapshotMergeBox;
use crate::mir::phi_core::phi_input_collector::PhiInputCollector;
use std::collections::HashMap;
/// 📦 LoopForm Context - Box-First理論に基づくパラメータ予約明示化
@ -341,13 +342,16 @@ impl LoopFormBuilder {
// we still materialize PHI inputs for all predecessors so that every edge
// into header has a corresponding value.
for pinned in &self.pinned {
let mut inputs: Vec<(BasicBlockId, ValueId)> =
vec![(self.preheader_id, pinned.preheader_copy)];
// Phase 26-B-3: Use PhiInputCollector for unified PHI input handling
let mut collector = PhiInputCollector::new();
// Add preheader input
collector.add_preheader(self.preheader_id, pinned.preheader_copy);
// Add inputs from each continue snapshot that carries this variable.
for (cid, snapshot) in continue_snapshots {
if let Some(&value) = snapshot.get(&pinned.name) {
inputs.push((*cid, value));
collector.add_snapshot(&[(*cid, value)]);
}
}
@ -356,13 +360,13 @@ impl LoopFormBuilder {
let latch_value = ops
.get_variable_at_block(&pinned.name, latch_id)
.unwrap_or(pinned.header_phi);
inputs.push((latch_id, latch_value));
collector.add_latch(latch_id, latch_value);
sanitize_phi_inputs(&mut inputs);
collector.sanitize();
// Step 5-4: φ縮約self-φ撲滅)
// 全入力が同じValueIdなら、PHI不要loop-invariant
if let Some(same_value) = LoopSnapshotMergeBox::optimize_same_value(&inputs) {
if let Some(same_value) = collector.optimize_same_value() {
if debug {
eprintln!(
"[loopform/seal_phis] OPTIMIZED pinned '{}': phi={:?} → same_value={:?} (loop-invariant)",
@ -374,6 +378,8 @@ impl LoopFormBuilder {
continue;
}
let inputs = collector.finalize();
if debug {
eprintln!(
"[loopform/seal_phis] pinned '{}' phi={:?} inputs={:?}",
@ -405,22 +411,27 @@ impl LoopFormBuilder {
})?
};
let mut inputs: Vec<(BasicBlockId, ValueId)> =
vec![(self.preheader_id, carrier.preheader_copy)];
// Phase 26-B-3: Use PhiInputCollector for unified PHI input handling
let mut collector = PhiInputCollector::new();
// Add preheader input
collector.add_preheader(self.preheader_id, carrier.preheader_copy);
// Add inputs from continue snapshots
for (cid, snapshot) in continue_snapshots {
if let Some(&value) = snapshot.get(&carrier.name) {
inputs.push((*cid, value));
collector.add_snapshot(&[(*cid, value)]);
}
}
inputs.push((latch_id, carrier.latch_value));
// Add latch input
collector.add_latch(latch_id, carrier.latch_value);
sanitize_phi_inputs(&mut inputs);
collector.sanitize();
// Step 5-4: φ縮約self-φ撲滅)
// 全入力が同じValueIdなら、PHI不要誤分類されたloop-invariant
if let Some(same_value) = LoopSnapshotMergeBox::optimize_same_value(&inputs) {
if let Some(same_value) = collector.optimize_same_value() {
if debug {
eprintln!(
"[loopform/seal_phis] OPTIMIZED carrier '{}': phi={:?} → same_value={:?} (misclassified as carrier, actually loop-invariant)",
@ -432,6 +443,8 @@ impl LoopFormBuilder {
continue;
}
let inputs = collector.finalize();
if debug {
eprintln!(
"[loopform/seal_phis] carrier '{}' phi={:?} inputs={:?}",
@ -599,17 +612,19 @@ impl LoopFormBuilder {
inspector,
)?;
// 4. PHI 生成(optimize_same_value と sanitize_inputs を使用)
for (var_name, mut inputs) in all_vars {
// 4. PHI 生成(Phase 26-B-3: PhiInputCollectorを使用)
for (var_name, inputs) in all_vars {
// Phase 26-B-3: Use PhiInputCollector for unified PHI input handling
let mut collector = PhiInputCollector::new();
collector.add_snapshot(&inputs);
collector.sanitize();
if debug {
eprintln!("[DEBUG/exit_phi] Variable '{}': {} inputs", var_name, inputs.len());
for (bb, val) in &inputs {
eprintln!("[DEBUG/exit_phi] pred={:?} val={:?}", bb, val);
}
eprintln!("[DEBUG/exit_phi] Variable '{}': {} inputs", var_name, collector.len());
}
// Phase 25.2: optimize_same_value() で最適化判定
if let Some(same_val) = LoopSnapshotMergeBox::optimize_same_value(&inputs) {
if let Some(same_val) = collector.optimize_same_value() {
// 全て同じ値 or 単一入力 → PHI 不要
if debug {
eprintln!("[DEBUG/exit_phi] Variable '{}': single/same value, direct binding to {:?}",
@ -618,18 +633,17 @@ impl LoopFormBuilder {
ops.update_var(var_name, same_val);
} else {
// 異なる値を持つ場合は PHI ノードを生成
// Phase 25.2: sanitize_inputs() で入力を正規化
LoopSnapshotMergeBox::sanitize_inputs(&mut inputs);
let final_inputs = collector.finalize();
let phi_id = ops.new_value();
if debug {
eprintln!("[DEBUG/exit_phi] Creating PHI {:?} for var '{}' with {} inputs",
phi_id, var_name, inputs.len());
for (bb, val) in &inputs {
phi_id, var_name, final_inputs.len());
for (bb, val) in &final_inputs {
eprintln!("[DEBUG/exit_phi] PHI input: pred={:?} val={:?}", bb, val);
}
}
ops.emit_phi(phi_id, inputs)?;
ops.emit_phi(phi_id, final_inputs)?;
ops.update_var(var_name, phi_id);
}
}
@ -697,20 +711,8 @@ pub trait LoopFormOps {
fn get_variable_at_block(&self, name: &str, block: BasicBlockId) -> Option<ValueId>;
}
/// Deduplicate PHI inputs by predecessor block and sort by block ID
///
/// Handles cases where multiple edges from same predecessor are merged
/// (e.g., continue + normal flow both going to header).
fn sanitize_phi_inputs(inputs: &mut Vec<(BasicBlockId, ValueId)>) {
let mut map: HashMap<BasicBlockId, ValueId> = HashMap::new();
for (bb, v) in inputs.iter().cloned() {
// Later entries override earlier ones
map.insert(bb, v);
}
let mut vec: Vec<(BasicBlockId, ValueId)> = map.into_iter().collect();
vec.sort_by_key(|(bb, _)| bb.as_u32());
*inputs = vec;
}
/// Phase 26-B-3: sanitize_phi_inputs() removed - replaced by PhiInputCollector
/// See: src/mir/phi_core/phi_input_collector.rs
/// Phase 25.1g: ControlForm-based wrapper for LoopForm Exit PHI generation.
/// This provides a thin adapter layer that accepts ControlForm and delegates
@ -762,19 +764,9 @@ mod tests {
use super::*;
use std::collections::HashMap;
#[test]
fn test_sanitize_phi_inputs() {
let mut inputs = vec![
(BasicBlockId::new(1), ValueId::new(10)),
(BasicBlockId::new(2), ValueId::new(20)),
(BasicBlockId::new(1), ValueId::new(11)), // Duplicate, should override
];
sanitize_phi_inputs(&mut inputs);
assert_eq!(inputs.len(), 2);
assert_eq!(inputs[0], (BasicBlockId::new(1), ValueId::new(11))); // Latest value
assert_eq!(inputs[1], (BasicBlockId::new(2), ValueId::new(20)));
}
// Phase 26-B-3: test_sanitize_phi_inputs() removed
// Replaced by PhiInputCollector::test_sanitize_removes_duplicates()
// See: src/mir/phi_core/phi_input_collector.rs
#[test]
fn test_loopform_builder_separation() {