feat(joinir): Phase 61-4-D/E function guard and toplevel emitter

Phase 61-4 追加実装:

1. Phase 61-4-D: 関数名ガード整理
   - is_joinir_if_toplevel_target() ヘルパー追加
   - IfSelectTest.*, IfToplevelTest.*, IfMergeTest.* 対応
   - if_form.rs で関数名チェック統合

2. Phase 61-4-E: emit_toplevel_phis() 追加
   - IfInLoopPhiEmitter に toplevel 用メソッド追加
   - carrier_names 不要(PhiSpec の全変数を対象)
   - HAKO_JOINIR_IF_TOPLEVEL_TRACE でトレース可能

現状:
- dry-run モードでパターンマッチング確認可能
- 本番経路のPHI生成統合は次フェーズ(MirBuilder PHI emit 方式検討必要)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
nyash-codex
2025-11-29 15:15:22 +09:00
parent b73413566d
commit 3439de0f65
3 changed files with 147 additions and 8 deletions

View File

@ -154,6 +154,110 @@ impl IfInLoopPhiEmitter {
Ok(phi_count)
}
/// Phase 61-4: ループ外 If PHI 生成Toplevel If
///
/// ループ外の純粋な if に対して PHI を生成する。
/// carrier_names が空のため、PhiSpec の全変数を対象とする。
///
/// # Arguments
///
/// * `phi_spec` - JoinIR から計算された PHI 仕様
/// * `pre_if_var_map` - if 直前の変数マップ
/// * `then_snapshot` - then 腕終了時の変数スナップショット
/// * `else_snapshot_opt` - else 腕終了時の変数スナップショット
/// * `ops` - PHI 生成操作インターフェース
/// * `if_shape` - If 構造情報
///
/// # Returns
///
/// 生成した PHI の数
pub fn emit_toplevel_phis<O: PhiBuilderOps>(
phi_spec: &PhiSpec,
pre_if_var_map: &BTreeMap<String, ValueId>,
then_snapshot: &BTreeMap<String, ValueId>,
else_snapshot_opt: Option<&BTreeMap<String, ValueId>>,
ops: &mut O,
if_shape: &IfShape,
) -> Result<usize, String> {
let mut phi_count = 0;
let trace_on =
std::env::var("HAKO_JOINIR_IF_TOPLEVEL_TRACE").ok().as_deref() == Some("1");
if trace_on {
eprintln!("[Phase 61-4] IfInLoopPhiEmitter::emit_toplevel_phis start");
eprintln!("[Phase 61-4] header_phis: {:?}", phi_spec.header_phis);
}
// Toplevel PHI 生成: PhiSpec の全変数を対象
for var_name in &phi_spec.header_phis {
// pre_if値を取得
let pre_val = match pre_if_var_map.get(var_name) {
Some(&v) => v,
None => {
if trace_on {
eprintln!(
"[Phase 61-4] ⚠️ var={} not found in pre_if_var_map, skipping",
var_name
);
}
continue;
}
};
// Then値: snapshot から取得、なければ pre_val
let then_val = then_snapshot.get(var_name).copied().unwrap_or(pre_val);
// Else値: snapshot から取得、なければ pre_val
let else_val = else_snapshot_opt
.and_then(|m| m.get(var_name).copied())
.unwrap_or(pre_val);
// 値が同一なら PHI 不要
if then_val == else_val {
if trace_on {
eprintln!(
"[Phase 61-4] var={}: then_val == else_val ({:?}), no PHI needed",
var_name, then_val
);
}
ops.update_var(var_name.clone(), then_val);
continue;
}
// PHI 生成
let phi_dst = ops.new_value();
let mut inputs = Vec::new();
// Then 入力
inputs.push((if_shape.then_block, then_val));
// Else 入力
if let Some(else_bb) = if_shape.else_block {
inputs.push((else_bb, else_val));
}
if trace_on {
eprintln!(
"[Phase 61-4] var={}: emit PHI dst={:?} inputs={:?}",
var_name, phi_dst, inputs
);
}
ops.emit_phi(if_shape.merge_block, phi_dst, inputs)?;
ops.update_var(var_name.clone(), phi_dst);
phi_count += 1;
}
if trace_on {
eprintln!(
"[Phase 61-4] IfInLoopPhiEmitter::emit_toplevel_phis done: {} PHIs",
phi_count
);
}
Ok(phi_count)
}
}
#[cfg(test)]