From 059533876e17f0470a77be8207f4cbb460acf775 Mon Sep 17 00:00:00 2001 From: nyash-codex Date: Thu, 20 Nov 2025 17:55:23 +0900 Subject: [PATCH] =?UTF-8?q?refactor(phi):=20Phase=2026-B-3=20-=20loopform?= =?UTF-8?q?=5Fbuilder.rs=E3=81=A7PhiInputCollector=E7=B5=B1=E5=90=88?= =?UTF-8?q?=E5=AE=8C=E4=BA=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- src/mir/phi_core/loopform_builder.rs | 94 +++++++++++++--------------- 1 file changed, 43 insertions(+), 51 deletions(-) diff --git a/src/mir/phi_core/loopform_builder.rs b/src/mir/phi_core/loopform_builder.rs index 8355521d..d559bb75 100644 --- a/src/mir/phi_core/loopform_builder.rs +++ b/src/mir/phi_core/loopform_builder.rs @@ -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; } -/// 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 = 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() {