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:
@ -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() {
|
||||
|
||||
Reference in New Issue
Block a user