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:
@ -1,7 +1,6 @@
|
|||||||
use super::{MirBuilder, ValueId};
|
use super::{MirBuilder, ValueId};
|
||||||
use crate::ast::ASTNode;
|
use crate::ast::ASTNode;
|
||||||
use crate::mir::loop_api::LoopBuilderApi; // for current_block()
|
use crate::mir::loop_api::LoopBuilderApi; // for current_block()
|
||||||
use std::collections::BTreeSet;
|
|
||||||
|
|
||||||
impl MirBuilder {
|
impl MirBuilder {
|
||||||
/// Lower an if/else using a structured IfForm (header→then/else→merge).
|
/// Lower an if/else using a structured IfForm (header→then/else→merge).
|
||||||
@ -141,10 +140,16 @@ impl MirBuilder {
|
|||||||
let joinir_dryrun = crate::config::env::joinir_if_toplevel_dryrun_enabled();
|
let joinir_dryrun = crate::config::env::joinir_if_toplevel_dryrun_enabled();
|
||||||
let mut joinir_success = false;
|
let mut joinir_success = false;
|
||||||
|
|
||||||
if joinir_enabled && (joinir_toplevel || joinir_dryrun) {
|
// 関数名ガードチェック
|
||||||
|
let func_name = self
|
||||||
|
.current_function
|
||||||
|
.as_ref()
|
||||||
|
.map(|f| f.signature.name.as_str())
|
||||||
|
.unwrap_or("");
|
||||||
|
let is_target = crate::mir::join_ir::lowering::is_joinir_if_toplevel_target(func_name);
|
||||||
|
|
||||||
|
if joinir_enabled && is_target && (joinir_toplevel || joinir_dryrun) {
|
||||||
if let Some(ref func) = self.current_function {
|
if let Some(ref func) = self.current_function {
|
||||||
// carrier_names: ループ外なので空集合(pure_if()使用)
|
|
||||||
let _carrier_names: BTreeSet<String> = BTreeSet::new(); // Phase 61-4: 将来の本番経路用
|
|
||||||
let context =
|
let context =
|
||||||
crate::mir::join_ir::lowering::if_phi_context::IfPhiContext::pure_if();
|
crate::mir::join_ir::lowering::if_phi_context::IfPhiContext::pure_if();
|
||||||
|
|
||||||
@ -157,8 +162,8 @@ impl MirBuilder {
|
|||||||
Some(join_inst) => {
|
Some(join_inst) => {
|
||||||
if joinir_dryrun || joinir_toplevel {
|
if joinir_dryrun || joinir_toplevel {
|
||||||
eprintln!(
|
eprintln!(
|
||||||
"[Phase 61-4] ✅ Toplevel If lowered via JoinIR: {:?}",
|
"[Phase 61-4] ✅ Toplevel If lowered via JoinIR ({}): {:?}",
|
||||||
join_inst
|
func_name, join_inst
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -176,7 +181,7 @@ impl MirBuilder {
|
|||||||
// 本番経路が有効な場合のみ success = true
|
// 本番経路が有効な場合のみ success = true
|
||||||
if joinir_toplevel {
|
if joinir_toplevel {
|
||||||
joinir_success = true;
|
joinir_success = true;
|
||||||
// TODO: Phase 61-4 本番経路のPHI生成
|
// TODO: Phase 61-4-E 本番経路のPHI生成
|
||||||
// 現時点では dry-run 的動作(フォールバック経路を使用)
|
// 現時点では dry-run 的動作(フォールバック経路を使用)
|
||||||
if joinir_dryrun {
|
if joinir_dryrun {
|
||||||
eprintln!("[Phase 61-4] ⚠️ Production path not yet implemented, using fallback");
|
eprintln!("[Phase 61-4] ⚠️ Production path not yet implemented, using fallback");
|
||||||
@ -186,7 +191,7 @@ impl MirBuilder {
|
|||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
if joinir_dryrun {
|
if joinir_dryrun {
|
||||||
eprintln!("[Phase 61-4] ⏭️ JoinIR pattern not matched, using fallback");
|
eprintln!("[Phase 61-4] ⏭️ JoinIR pattern not matched for {}, using fallback", func_name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -79,6 +79,36 @@ pub(crate) fn is_loop_lowered_function(name: &str) -> bool {
|
|||||||
LOOP_LOWERED_FUNCTIONS.contains(&name)
|
LOOP_LOWERED_FUNCTIONS.contains(&name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Phase 61-4: ループ外 If の JoinIR 対象関数判定
|
||||||
|
///
|
||||||
|
/// HAKO_JOINIR_IF_TOPLEVEL=1 有効時に、ループ外 if の JoinIR 経路を試行する関数。
|
||||||
|
/// 段階的に対象を拡大するため、最小限のホワイトリストから開始。
|
||||||
|
///
|
||||||
|
/// ## 対象関数
|
||||||
|
/// - IfSelectTest.*: テスト専用関数群
|
||||||
|
/// - IfToplevelTest.*: ループ外 if テスト専用(Phase 61-4)
|
||||||
|
/// - JsonShapeToMap._read_value_from_pair/1: Phase 33-4 で検証済み
|
||||||
|
///
|
||||||
|
/// ## 使用方法
|
||||||
|
/// if_form.rs から呼び出され、関数名がホワイトリストに含まれる場合のみ
|
||||||
|
/// JoinIR 経路を試行する。
|
||||||
|
pub fn is_joinir_if_toplevel_target(name: &str) -> bool {
|
||||||
|
// Test prefixes (always enabled)
|
||||||
|
if name.starts_with("IfSelectTest.")
|
||||||
|
|| name.starts_with("IfToplevelTest.")
|
||||||
|
|| name.starts_with("IfMergeTest.")
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Explicit approvals (Phase 33-4 verified)
|
||||||
|
matches!(
|
||||||
|
name,
|
||||||
|
"JsonShapeToMap._read_value_from_pair/1"
|
||||||
|
| "Stage1JsonScannerBox.value_start_after_key_pos/2"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
/// Phase 33-7: Try to lower if/else to JoinIR Select/IfMerge instruction
|
/// Phase 33-7: Try to lower if/else to JoinIR Select/IfMerge instruction
|
||||||
///
|
///
|
||||||
/// Scope:
|
/// Scope:
|
||||||
|
|||||||
@ -154,6 +154,110 @@ impl IfInLoopPhiEmitter {
|
|||||||
|
|
||||||
Ok(phi_count)
|
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)]
|
#[cfg(test)]
|
||||||
|
|||||||
Reference in New Issue
Block a user