//! PHI Merge Helper - Unified PHI insertion logic //! //! Phase 25.1q: PhiMergeHelper統一化 //! - phi.rs の2箇所のPHI insertion重複(L120-137 vs L155-174)を統一 //! - Conservative戦略によるvariable merging の一元化 //! //! Box-First理論: PHI insertion の境界を明確にし、差し替え可能な箱として提供 use super::{BasicBlockId, MirBuilder, ValueId}; use std::collections::BTreeMap; // Phase 25.1: 決定性確保 /// PHI Merge Helper - 統一PHI挿入ロジック(Conservative戦略) /// /// # Purpose /// - 複数のブランチ出口からマージブロックへのPHI挿入を統一処理 /// - Conservative戦略: 全変数に対してPHIを生成(correctness-first) /// /// # Usage /// ```ignore /// let mut helper = PhiMergeHelper::new(&mut builder, then_exit, else_exit); /// helper.merge_variable("x".to_string(), then_v, else_v)?; /// ``` pub struct PhiMergeHelper<'a> { builder: &'a mut MirBuilder, then_exit: Option, else_exit: Option, } impl<'a> PhiMergeHelper<'a> { /// Create a new PhiMergeHelper /// /// # Arguments /// * `builder` - MirBuilder instance /// * `then_exit` - Then-branch exit block (None if unreachable) /// * `else_exit` - Else-branch exit block (None if unreachable) pub fn new( builder: &'a mut MirBuilder, then_exit: Option, else_exit: Option, ) -> Self { Self { builder, then_exit, else_exit, } } /// Merge a single variable using Conservative PHI strategy /// /// # Arguments /// * `name` - Variable name /// * `then_v` - Value from then-branch /// * `else_v` - Value from else-branch /// /// # Returns /// Ok(()) on success, Err(String) on failure /// /// # Conservative Strategy /// - 0 predecessors: skip (unreachable) /// - 1 predecessor: direct insert (no PHI needed) /// - 2+ predecessors: insert PHI node pub fn merge_variable( &mut self, name: String, then_v: ValueId, else_v: ValueId, ) -> Result<(), String> { let mut inputs: Vec<(BasicBlockId, ValueId)> = Vec::new(); if let Some(tp) = self.then_exit { inputs.push((tp, then_v)); } if let Some(ep) = self.else_exit { inputs.push((ep, else_v)); } match inputs.len() { 0 => { // Both branches unreachable - skip Ok(()) } 1 => { // Single predecessor - direct insert (no PHI) let (_pred, v) = inputs[0]; self.builder.variable_map.insert(name, v); Ok(()) } _ => { // Multiple predecessors - insert PHI if let Some(func) = self.builder.current_function.as_mut() { func.update_cfg(); } if let (Some(func), Some(cur_bb)) = (&self.builder.current_function, self.builder.current_block) { crate::mir::phi_core::common::debug_verify_phi_inputs(func, cur_bb, &inputs); } let merged = self.builder.insert_phi(inputs)?; self.builder.variable_map.insert(name, merged); Ok(()) } } } /// Merge a variable with explicit destination ValueId (for primary result) /// /// # Arguments /// * `dst` - Destination ValueId for PHI result /// * `then_v` - Value from then-branch /// * `else_v` - Value from else-branch /// /// # Returns /// Ok(()) on success, Err(String) on failure #[allow(dead_code)] // Reserved: explicit dst PHI merge for future use pub fn merge_with_dst( &mut self, dst: ValueId, then_v: ValueId, else_v: ValueId, ) -> Result<(), String> { let mut inputs: Vec<(BasicBlockId, ValueId)> = Vec::new(); if let Some(tp) = self.then_exit { inputs.push((tp, then_v)); } if let Some(ep) = self.else_exit { inputs.push((ep, else_v)); } match inputs.len() { 0 | 1 => { // Should not happen for explicit dst merge Ok(()) } _ => { // Insert PHI with explicit dst if let Some(func) = self.builder.current_function.as_mut() { func.update_cfg(); } if let (Some(func), Some(cur_bb)) = (&self.builder.current_function, self.builder.current_block) { crate::mir::phi_core::common::debug_verify_phi_inputs(func, cur_bb, &inputs); } self.builder.insert_phi_with_dst(dst, inputs)?; Ok(()) } } } /// Merge all variables from both branches (Conservative strategy) /// /// # Arguments /// * `pre_if_snapshot` - Variable map before if statement /// * `then_map_end` - Variable map at end of then-branch /// * `else_map_end_opt` - Variable map at end of else-branch (None for empty else) /// * `skip_var` - Optional variable name to skip (already merged elsewhere) /// /// # Returns /// Ok(()) on success, Err(String) on failure pub fn merge_all_vars( &mut self, pre_if_snapshot: &BTreeMap, // Phase 25.1: BTreeMap化 then_map_end: &BTreeMap, // Phase 25.1: BTreeMap化 else_map_end_opt: &Option>, // Phase 25.1: BTreeMap化 skip_var: Option<&str>, ) -> Result<(), String> { // Use Conservative strategy from conservative module let conservative = crate::mir::phi_core::conservative::ConservativeMerge::analyze( pre_if_snapshot, then_map_end, else_map_end_opt, ); // Phase 42: trace_if_enabled 削除(下の trace_conservative と重複していたため) let trace_conservative = std::env::var("NYASH_CONSERVATIVE_PHI_TRACE") .ok() .as_deref() == Some("1"); for name in &conservative.all_vars { if skip_var.map(|s| s == name.as_str()).unwrap_or(false) { if trace_conservative { eprintln!("[Conservative PHI] Skipping {}: matches skip_var", name); } continue; } let pre_val_opt = pre_if_snapshot.get(name.as_str()).copied(); let then_v_opt = then_map_end.get(name.as_str()).copied().or(pre_val_opt); let else_v_opt = else_map_end_opt .as_ref() .and_then(|m| m.get(name.as_str()).copied()) .or(pre_val_opt); let (then_v, else_v) = match (then_v_opt, else_v_opt) { (Some(tv), Some(ev)) => { if trace_conservative { eprintln!( "[Conservative PHI] Generating PHI for {}: then={:?} else={:?}", name, tv, ev ); } (tv, ev) } (Some(tv), None) => { let undef = crate::mir::builder::emission::constant::emit_void(self.builder); if trace_conservative { eprintln!( "[Conservative PHI] One-branch variable {}: then={:?} else=void({:?})", name, tv, undef ); } (tv, undef) } (None, Some(ev)) => { let undef = crate::mir::builder::emission::constant::emit_void(self.builder); if trace_conservative { eprintln!( "[Conservative PHI] One-branch variable {}: then=void({:?}) else={:?}", name, undef, ev ); } (undef, ev) } (None, None) => { if trace_conservative { eprintln!("[Conservative PHI] Skipping {}: undefined everywhere", name); } continue; } }; self.merge_variable(name.clone(), then_v, else_v)?; } Ok(()) } }