2025-11-19 10:32:16 +09:00
|
|
|
|
//! 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 の一貫性保証
|
2025-11-28 07:30:01 +09:00
|
|
|
|
//!
|
|
|
|
|
|
//! # Phase 35-39 PHI削減計画
|
|
|
|
|
|
//!
|
|
|
|
|
|
//! ## 概要
|
|
|
|
|
|
//!
|
|
|
|
|
|
//! Conservative ∘ Elimination = Minimal SSA の理論に基づく保守的PHI生成。
|
|
|
|
|
|
//! 非対称分岐(else なし)での void emission と predecessor fallback を扱う。
|
|
|
|
|
|
//!
|
|
|
|
|
|
//! ## 🔜 Phase 40で部分削除予定(Level 2、30行)
|
|
|
|
|
|
//!
|
|
|
|
|
|
//! - ConservativeMerge struct inline (30行)
|
|
|
|
|
|
//! - **Phase 40-4**: JoinIrConservativeAnalyzerに吸収
|
|
|
|
|
|
//! - **保持**: 理論コメント、Conservative ∘ Elimination説明
|
|
|
|
|
|
//! - **削除**: 構造体定義、実装コード
|
|
|
|
|
|
//!
|
|
|
|
|
|
//! ## ⏳ Phase 41+で完全削除予定(Level 3、約138行)
|
|
|
|
|
|
//!
|
|
|
|
|
|
//! - 残りのconservative logic全て
|
|
|
|
|
|
//! - **削除条件**: JoinIR Verifier完全移行
|
|
|
|
|
|
//! - **難易度**: MEDIUM-HIGH
|
|
|
|
|
|
//!
|
|
|
|
|
|
//! ## 参照
|
|
|
|
|
|
//!
|
|
|
|
|
|
//! - Phase 37分析: `docs/.../phase-37-if-phi-reduction/conservative_responsibility_table.md`
|
|
|
|
|
|
//! - Phase 39設計: `docs/.../phase-39-if-phi-level2/joinir_extension_design.md`
|
2025-11-19 10:32:16 +09:00
|
|
|
|
|
|
|
|
|
|
use crate::mir::ValueId;
|
2025-11-22 05:33:40 +09:00
|
|
|
|
use std::collections::{BTreeMap, HashSet}; // Phase 25.1: BTreeMap化
|
2025-11-19 10:32:16 +09:00
|
|
|
|
|
|
|
|
|
|
/// Conservative PHI 戦略による変数マージ分析
|
2025-11-28 07:30:01 +09:00
|
|
|
|
///
|
|
|
|
|
|
/// # Phase 40削減計画
|
|
|
|
|
|
///
|
|
|
|
|
|
/// - **Phase 40-4**: JoinIrConservativeAnalyzerにインライン化
|
|
|
|
|
|
/// - **削減効果**: 30行(構造体定義+実装)
|
|
|
|
|
|
/// - **保持**: Conservative ∘ Elimination理論コメント
|
2025-11-19 10:32:16 +09:00
|
|
|
|
pub struct ConservativeMerge {
|
2025-11-28 07:30:01 +09:00
|
|
|
|
// TODO(Phase 40-4): JoinIrConservativeAnalyzerに移行予定
|
2025-11-19 10:32:16 +09:00
|
|
|
|
/// 全ブランチに存在する変数のユニオン(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)
|
2025-11-28 07:30:01 +09:00
|
|
|
|
///
|
|
|
|
|
|
/// # Phase 40-2で使用される(compute_modified_names削除時)
|
2025-11-19 10:32:16 +09:00
|
|
|
|
pub fn analyze(
|
2025-11-24 14:17:02 +09:00
|
|
|
|
pre_if: &BTreeMap<String, ValueId>, // Phase 25.1: BTreeMap化
|
2025-11-22 05:33:40 +09:00
|
|
|
|
then_end: &BTreeMap<String, ValueId>, // Phase 25.1: BTreeMap化
|
|
|
|
|
|
else_end_opt: &Option<BTreeMap<String, ValueId>>, // Phase 25.1: BTreeMap化
|
2025-11-19 10:32:16 +09:00
|
|
|
|
) -> Self {
|
2025-11-28 07:30:01 +09:00
|
|
|
|
// TODO(Phase 40-2/40-4): JoinIR Verifierに移行
|
|
|
|
|
|
|
2025-11-19 10:32:16 +09:00
|
|
|
|
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());
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-21 06:25:17 +09:00
|
|
|
|
let changed =
|
|
|
|
|
|
crate::mir::phi_core::if_phi::compute_modified_names(pre_if, then_end, else_end_opt);
|
2025-11-19 10:32:16 +09:00
|
|
|
|
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,
|
2025-11-22 05:33:40 +09:00
|
|
|
|
pre_if: &BTreeMap<String, ValueId>, // Phase 25.1: BTreeMap化
|
|
|
|
|
|
then_end: &BTreeMap<String, ValueId>, // Phase 25.1: BTreeMap化
|
|
|
|
|
|
else_end_opt: &Option<BTreeMap<String, ValueId>>, // Phase 25.1: BTreeMap化
|
2025-11-19 10:32:16 +09:00
|
|
|
|
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生成の可視化)
|
2025-11-21 06:25:17 +09:00
|
|
|
|
pub fn trace_if_enabled(
|
|
|
|
|
|
&self,
|
2025-11-22 05:33:40 +09:00
|
|
|
|
pre_if: &BTreeMap<String, ValueId>, // Phase 25.1: BTreeMap化
|
|
|
|
|
|
then_end: &BTreeMap<String, ValueId>, // Phase 25.1: BTreeMap化
|
|
|
|
|
|
else_end_opt: &Option<BTreeMap<String, ValueId>>, // Phase 25.1: BTreeMap化
|
2025-11-21 06:25:17 +09:00
|
|
|
|
) {
|
2025-11-19 10:32:16 +09:00
|
|
|
|
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() {
|
2025-11-22 05:33:40 +09:00
|
|
|
|
let mut pre_if = BTreeMap::new();
|
2025-11-19 10:32:16 +09:00
|
|
|
|
pre_if.insert("x".to_string(), ValueId::new(1));
|
|
|
|
|
|
|
2025-11-22 05:33:40 +09:00
|
|
|
|
let mut then_end = BTreeMap::new();
|
2025-11-19 10:32:16 +09:00
|
|
|
|
then_end.insert("x".to_string(), ValueId::new(2));
|
|
|
|
|
|
|
2025-11-22 05:33:40 +09:00
|
|
|
|
let mut else_end = BTreeMap::new();
|
2025-11-19 10:32:16 +09:00
|
|
|
|
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() {
|
2025-11-22 05:33:40 +09:00
|
|
|
|
let pre_if = BTreeMap::new();
|
2025-11-19 10:32:16 +09:00
|
|
|
|
|
2025-11-22 05:33:40 +09:00
|
|
|
|
let mut then_end = BTreeMap::new();
|
2025-11-19 10:32:16 +09:00
|
|
|
|
then_end.insert("x".to_string(), ValueId::new(1));
|
|
|
|
|
|
|
2025-11-22 05:33:40 +09:00
|
|
|
|
let mut else_end = BTreeMap::new();
|
2025-11-19 10:32:16 +09:00
|
|
|
|
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"));
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|