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() {