Files
hakorune/src/mir/phi_core/conservative.rs

169 lines
5.7 KiB
Rust
Raw Normal View History

//! Conservative PHI Generation - Box Theory Application
//!
//! Theory: Conservative ∘ Elimination = Minimal SSA
//! - Conservative (this): correctness-first, generate all PHIs
//! - Elimination (future): efficiency optimization, remove unused PHIs
//!
//! Phase 25.1q: Conservative PHI戦略の一元化
//! - phi.rs の Conservative PHI ロジックL23-117を統一
//! - void emission、predecessor fallback の一貫性保証
use crate::mir::ValueId;
use std::collections::{HashMap, HashSet};
/// Conservative PHI 戦略による変数マージ分析
pub struct ConservativeMerge {
/// 全ブランチに存在する変数のユニオンConservative戦略
pub all_vars: HashSet<String>,
/// 実際に変更された変数のセット(デバッグ/ヒント用)
pub changed_vars: HashSet<String>,
}
impl ConservativeMerge {
/// 全変数のユニオンを計算Conservative戦略
///
/// # Arguments
/// * `pre_if` - if文前のスナップショット
/// * `then_end` - then-branch終了時の変数マップ
/// * `else_end_opt` - else-branch終了時の変数マップNoneの場合はempty else
pub fn analyze(
pre_if: &HashMap<String, ValueId>,
then_end: &HashMap<String, ValueId>,
else_end_opt: &Option<HashMap<String, ValueId>>,
) -> Self {
let mut all_vars = HashSet::new();
all_vars.extend(pre_if.keys().cloned());
all_vars.extend(then_end.keys().cloned());
if let Some(ref else_map) = else_end_opt {
all_vars.extend(else_map.keys().cloned());
}
let changed =
crate::mir::phi_core::if_phi::compute_modified_names(pre_if, then_end, else_end_opt);
let changed_vars = changed.into_iter().collect();
Self {
all_vars,
changed_vars,
}
}
/// Conservative フォールバック値取得
///
/// # Returns
/// * `Some((then_v, else_v))` - 両ブランチの値void emission 含む)
/// * `None` - どこにも定義されていない変数(スキップ)
///
/// # Conservative Rules
/// 1. Both defined: use both values
/// 2. Only then: use then + void
/// 3. Only else: use void + else
/// 4. Neither: skip (return None)
pub fn get_conservative_values<F>(
&self,
name: &str,
pre_if: &HashMap<String, ValueId>,
then_end: &HashMap<String, ValueId>,
else_end_opt: &Option<HashMap<String, ValueId>>,
emit_void: F,
) -> Option<(ValueId, ValueId)>
where
F: Fn() -> ValueId,
{
let pre_val_opt = pre_if.get(name).copied();
// Fallback to predecessor value if not defined in a branch
let then_v_opt = then_end.get(name).copied().or(pre_val_opt);
let else_v_opt = else_end_opt
.as_ref()
.and_then(|m| m.get(name).copied())
.or(pre_val_opt);
match (then_v_opt, else_v_opt) {
(Some(tv), Some(ev)) => Some((tv, ev)),
(Some(tv), None) => {
// Variable exists in then branch but not else or predecessor
// Emit a 'const void' instruction to represent undefined value
Some((tv, emit_void()))
}
(None, Some(ev)) => {
// Variable exists in else branch but not then or predecessor
// Emit a 'const void' instruction to represent undefined value
Some((emit_void(), ev))
}
(None, None) => {
// Variable doesn't exist anywhere - skip
None
}
}
}
/// Debug trace 出力Conservative PHI生成の可視化
pub fn trace_if_enabled(
&self,
pre_if: &HashMap<String, ValueId>,
then_end: &HashMap<String, ValueId>,
else_end_opt: &Option<HashMap<String, ValueId>>,
) {
let trace_conservative = std::env::var("NYASH_CONSERVATIVE_PHI_TRACE")
.ok()
.as_deref()
== Some("1");
if trace_conservative {
eprintln!("[Conservative PHI] all_vars count: {}", self.all_vars.len());
eprintln!(
"[Conservative PHI] pre_if_snapshot: {:?}",
pre_if.keys().collect::<Vec<_>>()
);
eprintln!(
"[Conservative PHI] then_map_end: {:?}",
then_end.keys().collect::<Vec<_>>()
);
if let Some(ref else_map) = else_end_opt {
eprintln!(
"[Conservative PHI] else_map_end: {:?}",
else_map.keys().collect::<Vec<_>>()
);
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_conservative_merge_both_defined() {
let mut pre_if = HashMap::new();
pre_if.insert("x".to_string(), ValueId::new(1));
let mut then_end = HashMap::new();
then_end.insert("x".to_string(), ValueId::new(2));
let mut else_end = HashMap::new();
else_end.insert("x".to_string(), ValueId::new(3));
let merge = ConservativeMerge::analyze(&pre_if, &then_end, &Some(else_end));
assert_eq!(merge.all_vars.len(), 1);
assert!(merge.all_vars.contains("x"));
}
#[test]
fn test_conservative_merge_union() {
let pre_if = HashMap::new();
let mut then_end = HashMap::new();
then_end.insert("x".to_string(), ValueId::new(1));
let mut else_end = HashMap::new();
else_end.insert("y".to_string(), ValueId::new(2));
let merge = ConservativeMerge::analyze(&pre_if, &then_end, &Some(else_end));
assert_eq!(merge.all_vars.len(), 2);
assert!(merge.all_vars.contains("x"));
assert!(merge.all_vars.contains("y"));
}
}