feat(phi): Phase 26-F Step 1 & 3 - BodyLocal if-merge統合(WIP - 過剰フィルタリング発生中)

Step 1完了:
- body_local_phi_builder.rs: filter_if_merge_candidates() API追加
- pre_if/then_end/else_end_opt/reachable_preds受け取り
- LoopVarClassBox使用して変数分類

Step 3完了:
- loop_builder.rs: BodyLocalPhiBuilder作成・PhiBuilderBoxに設定
- phi_builder_box.rs: IfPhiContext拡張・set_body_local_filter()実装
- compute_modified_names_if()でフィルタリング適用

**問題**: LocalScopeInspectorBox空のため全候補フィルタリング(0 candidates)

技術詳細:
- inspector定義記録なし → classify誤判定 → 全変数BodyLocalInternal扱い
- テスト結果: bb54/bb52→bb38/bb36/bb32(ブロック番号変化=PHI生成影響あり)
- mir_stage1_using_resolver_modules_map_continue_break_with_lookup_verifies: PASS
- mir_stage1_using_resolver_resolve_with_modules_map_verifies: FAIL(domination error残存)

次のステップ:
1. filter_if_merge_candidates()単純実装(inspector不要)
2. または変数定義トラッキング実装
3. ChatGPT相談推奨
This commit is contained in:
nyash-codex
2025-11-22 09:05:31 +09:00
parent 879134fe3c
commit cbe6bf0140
4 changed files with 277 additions and 6 deletions

View File

@ -1147,9 +1147,23 @@ impl<'a> LoopBuilder<'a> {
let mut ops = Ops(self);
// Phase 26-F: BodyLocalPhiBuilder setup for if-merge PHI filtering
// Purpose: Filter out BodyLocalInternal variables (defined in only some branches)
let inspector = crate::mir::phi_core::local_scope_inspector::LocalScopeInspectorBox::new();
let classifier = crate::mir::phi_core::loop_var_classifier::LoopVarClassBox::new();
let body_local_builder =
crate::mir::phi_core::body_local_phi_builder::BodyLocalPhiBuilder::new(
classifier,
inspector,
);
// Phase 26-E: PhiBuilderBox SSOT統合If PHI生成
// Legacy: merge_modified_with_control() → New: PhiBuilderBox::generate_phis()
let mut phi_builder = crate::mir::phi_core::phi_builder_box::PhiBuilderBox::new();
// Phase 26-F: Set BodyLocal filter for PHI generation
phi_builder.set_body_local_filter(body_local_builder);
let post_snapshots = if let Some(ref else_map) = else_var_map_end_opt {
vec![then_var_map_end.clone(), else_map.clone()]
} else {

View File

@ -37,6 +37,7 @@ use crate::mir::BasicBlockId;
/// // Generate exit PHI
/// }
/// ```
#[derive(Clone)]
pub struct BodyLocalPhiBuilder {
/// Variable classifier
classifier: LoopVarClassBox,
@ -151,6 +152,86 @@ impl BodyLocalPhiBuilder {
.collect()
}
/// Filter variables for if-merge PHI generation (Phase 26-F)
///
/// # Purpose
/// IfForm body内のif-merge地点でPHI生成すべき変数をフィルタリング。
/// BodyLocalInternal変数一部ブランチでのみ定義はPHI候補から除外。
///
/// # Arguments
/// * `pre_if` - if直前のvariable_map
/// * `then_end` - thenブランチ終端時のvariable_map
/// * `else_end_opt` - elseブランチ終端時のvariable_mapなければNone
/// * `reachable_preds` - mergeに到達するpredブロック一覧breakで終わるブランチは含めない
///
/// # Returns
/// PHI生成すべき変数名のリスト
///
/// # Classification Logic
/// - Pinned: 常にPHI生成ループ外から来る変数
/// - Carrier: 常にPHI生成ループ内で更新される変数
/// - BodyLocalExit: 全ブランチで定義 → PHI生成
/// - BodyLocalInternal: 一部ブランチでのみ定義 → PHI生成しない
///
/// # Example
/// ```ignore
/// // if (cond) { ch = read() } else { /* ch未定義 */ }
/// // この場合、chはBodyLocalInternal → PHI候補から除外
///
/// use std::collections::BTreeMap;
/// let pre_if = BTreeMap::new();
/// let mut then_end = BTreeMap::new();
/// then_end.insert("ch".to_string(), ValueId(5));
/// let else_end_opt = Some(BTreeMap::new()); // chなし
///
/// let phi_vars = builder.filter_if_merge_candidates(
/// &pre_if,
/// &then_end,
/// &else_end_opt,
/// &[BasicBlockId(2), BasicBlockId(3)],
/// );
/// // Result: [] - "ch"はBodyLocalInternalなので除外
/// ```
pub fn filter_if_merge_candidates(
&self,
pre_if: &std::collections::BTreeMap<String, crate::mir::ValueId>,
then_end: &std::collections::BTreeMap<String, crate::mir::ValueId>,
else_end_opt: &Option<std::collections::BTreeMap<String, crate::mir::ValueId>>,
reachable_preds: &[BasicBlockId],
) -> Vec<String> {
use std::collections::BTreeSet;
// 1. 全ての変数名を収集pre_if + then_end + else_end_opt
let mut all_vars = BTreeSet::new();
all_vars.extend(pre_if.keys().cloned());
all_vars.extend(then_end.keys().cloned());
if let Some(else_end) = else_end_opt {
all_vars.extend(else_end.keys().cloned());
}
// 2. 各変数を分類してBodyLocalInternal以外を残す
all_vars
.into_iter()
.filter(|var_name| {
// LoopVarClassBox::classify を使用
// pinned_vars/carrier_varsは空if内のローカル変数のみ対象
let class = self.classifier.classify(
var_name,
&[], // pinned_varsif-merge時は通常空
&[], // carrier_varsif-merge時は通常空
&self.inspector,
reachable_preds,
);
// BodyLocalInternalはスキップ、それ以外はPHI生成
match class {
LoopVarClass::BodyLocalInternal => false,
_ => true,
}
})
.collect()
}
/// Get mutable reference to inspector
///
/// # Purpose

View File

@ -55,11 +55,19 @@ pub struct PhiBuilderBox {
loop_context: Option<LoopPhiContext>,
}
/// If PHI生成コンテキスト将来拡張
#[derive(Debug, Clone)]
/// If PHI生成コンテキストPhase 26-F拡張)
#[derive(Clone)]
struct IfPhiContext {
/// 予約済み(Phase 2で実装
_reserved: (),
/// Phase 26-F: BodyLocal変数フィルターBodyLocalInternal除外用
body_local_filter: Option<crate::mir::phi_core::body_local_phi_builder::BodyLocalPhiBuilder>,
}
impl std::fmt::Debug for IfPhiContext {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("IfPhiContext")
.field("body_local_filter", &self.body_local_filter.is_some())
.finish()
}
}
/// Loop PHI生成コンテキスト将来拡張用
@ -78,6 +86,30 @@ impl PhiBuilderBox {
}
}
/// Set BodyLocal filter for If PHI generation (Phase 26-F)
///
/// # Purpose
/// If-merge PHI生成時にBodyLocalInternal変数をフィルタリング。
/// BodyLocalPhiBuilderを使って、一部ブランチでのみ定義された変数を除外。
///
/// # Arguments
/// * `filter` - BodyLocalPhiBuilder instance for filtering
///
/// # Usage
/// ```ignore
/// let mut phi_builder = PhiBuilderBox::new();
/// phi_builder.set_body_local_filter(body_local_builder);
/// phi_builder.generate_phis(&mut ops, &form, &pre, &post)?;
/// ```
pub fn set_body_local_filter(
&mut self,
filter: crate::mir::phi_core::body_local_phi_builder::BodyLocalPhiBuilder,
) {
self.if_context = Some(IfPhiContext {
body_local_filter: Some(filter),
});
}
/// ControlFormベースの統一PHI生成エントリーポイント
///
/// # Arguments
@ -162,7 +194,12 @@ impl PhiBuilderBox {
}
// Compute modified variables (決定的順序: BTreeSet使用)
let modified_vars = self.compute_modified_names_if(pre_snapshot, then_end, &else_end_opt);
let modified_vars = self.compute_modified_names_if(
pre_snapshot,
then_end,
&else_end_opt,
if_shape,
);
for var_name in modified_vars {
// Conservative strategy: get values with void fallback
@ -209,16 +246,24 @@ impl PhiBuilderBox {
Ok(())
}
/// Compute modified variable names for If (決定的順序)
/// Compute modified variable names for If (決定的順序 + Phase 26-F filtering)
///
/// # Arguments
/// * `pre_snapshot` - if直前の変数スナップショット
/// * `then_end` - thenブランチ終端の変数スナップショット
/// * `else_end_opt` - elseブランチ終端の変数スナップショットなければNone
/// * `if_shape` - IfShapereachable_preds取得用
///
/// # Returns
///
/// ソート済みの変更変数名リストBTreeSetにより決定的
/// Phase 26-F: BodyLocalInternal変数はフィルタリングで除外
fn compute_modified_names_if(
&self,
pre_snapshot: &BTreeMap<String, ValueId>,
then_end: &BTreeMap<String, ValueId>,
else_end_opt: &Option<&BTreeMap<String, ValueId>>,
if_shape: &IfShape,
) -> Vec<String> {
use std::collections::BTreeSet;
@ -248,6 +293,39 @@ impl PhiBuilderBox {
}
}
// Phase 26-F: BodyLocalPhiBuilderフィルター適用
if let Some(ref ctx) = self.if_context {
if let Some(ref filter) = ctx.body_local_filter {
// reachable_preds取得then_block と else_block
let mut reachable_preds = Vec::new();
if let Some(then_block) = if_shape.then_block.into() {
reachable_preds.push(then_block);
}
if let Some(else_block) = if_shape.else_block {
reachable_preds.push(else_block);
}
// else_end_optをOption<BTreeMap>に変換
let else_end_owned = else_end_opt.map(|m| m.clone());
// BodyLocalPhiBuilderでフィルタリング
changed = filter.filter_if_merge_candidates(
pre_snapshot,
then_end,
&else_end_owned,
&reachable_preds,
);
// Debug trace
if std::env::var("NYASH_IF_TRACE").ok().as_deref() == Some("1") {
eprintln!(
"[PhiBuilderBox/if] BodyLocal filtering applied, {} candidates",
changed.len()
);
}
}
}
changed
}