diff --git a/src/config/env.rs b/src/config/env.rs index 7da7246f..2554b059 100644 --- a/src/config/env.rs +++ b/src/config/env.rs @@ -294,6 +294,33 @@ pub fn joinir_if_in_loop_enable() -> bool { env_bool("HAKO_JOINIR_IF_IN_LOOP_ENABLE") } +/// Phase 61-4: ループ外If JoinIR経路有効化 +/// +/// `HAKO_JOINIR_IF_TOPLEVEL=1` でループ外IfのJoinIR経路を有効化 +/// +/// 動作: +/// - ON: try_lower_if_to_joinir経路(if_form.rsで使用) +/// - OFF: PhiBuilderBox経路(既存) +/// +/// 前提条件: +/// - HAKO_JOINIR_IF_SELECT=1(Phase 33基盤) +/// +/// デフォルト: OFF(安全第一) +pub fn joinir_if_toplevel_enabled() -> bool { + env_bool("HAKO_JOINIR_IF_TOPLEVEL") +} + +/// Phase 61-4: ループ外If JoinIR dry-run有効化 +/// +/// `HAKO_JOINIR_IF_TOPLEVEL_DRYRUN=1` でdry-runモードを有効化 +/// +/// dry-runモード: +/// - JoinIR経路を試行しログ出力 +/// - 実際のPHI生成は既存経路を使用(安全) +pub fn joinir_if_toplevel_dryrun_enabled() -> bool { + env_bool("HAKO_JOINIR_IF_TOPLEVEL_DRYRUN") +} + // VM legacy by-name call fallback was removed (Phase 2 complete). // Phase 40-4.1: use_joinir_for_array_filter() removed (Route B now default). diff --git a/src/mir/builder/if_form.rs b/src/mir/builder/if_form.rs index 8ed36a61..66433a31 100644 --- a/src/mir/builder/if_form.rs +++ b/src/mir/builder/if_form.rs @@ -1,6 +1,7 @@ use super::{MirBuilder, ValueId}; use crate::ast::ASTNode; use crate::mir::loop_api::LoopBuilderApi; // for current_block() +use std::collections::BTreeSet; impl MirBuilder { /// Lower an if/else using a structured IfForm (header→then/else→merge). @@ -134,28 +135,92 @@ impl MirBuilder { let assigned_else_pre: Option = None; let pre_then_var_value: Option = None; - let result_val = self.normalize_if_else_phi( - then_block, - else_block, - if then_reaches_merge { - Some(then_exit_block) - } else { - None - }, - if else_reaches_merge { - Some(else_exit_block) - } else { - None - }, - then_value_raw, - else_value_raw, - &pre_if_var_map, - &then_ast_for_analysis, - &else_ast_for_analysis, - &then_var_map_end, - &else_var_map_end_opt, - pre_then_var_value, - )?; + // Phase 61-4: JoinIR 経路試行(ループ外 If) + let joinir_enabled = crate::config::env::joinir_if_select_enabled(); + let joinir_toplevel = crate::config::env::joinir_if_toplevel_enabled(); + let joinir_dryrun = crate::config::env::joinir_if_toplevel_dryrun_enabled(); + let mut joinir_success = false; + + if joinir_enabled && (joinir_toplevel || joinir_dryrun) { + if let Some(ref func) = self.current_function { + // carrier_names: ループ外なので空集合(pure_if()使用) + let _carrier_names: BTreeSet = BTreeSet::new(); // Phase 61-4: 将来の本番経路用 + let context = + crate::mir::join_ir::lowering::if_phi_context::IfPhiContext::pure_if(); + + match crate::mir::join_ir::lowering::try_lower_if_to_joinir( + func, + pre_branch_bb, + false, + Some(&context), + ) { + Some(join_inst) => { + if joinir_dryrun || joinir_toplevel { + eprintln!( + "[Phase 61-4] ✅ Toplevel If lowered via JoinIR: {:?}", + join_inst + ); + } + + // PhiSpec 計算 + let phi_spec = crate::mir::join_ir::lowering::if_phi_spec::compute_phi_spec_from_joinir(&context, &join_inst); + + if joinir_dryrun { + eprintln!( + "[Phase 61-4] 🔍 dry-run: JoinIR PhiSpec header={}, exit={}", + phi_spec.header_count(), + phi_spec.exit_count() + ); + } + + // 本番経路が有効な場合のみ success = true + if joinir_toplevel { + joinir_success = true; + // TODO: Phase 61-4 本番経路のPHI生成 + // 現時点では dry-run 的動作(フォールバック経路を使用) + if joinir_dryrun { + eprintln!("[Phase 61-4] ⚠️ Production path not yet implemented, using fallback"); + } + joinir_success = false; // フォールバック使用 + } + } + None => { + if joinir_dryrun { + eprintln!("[Phase 61-4] ⏭️ JoinIR pattern not matched, using fallback"); + } + } + } + } + } + + // Phase 61-4: JoinIR成功時はスキップ、失敗時は既存経路 + let result_val = if joinir_success { + // JoinIR 経路(未実装 - フォールバック) + crate::mir::builder::emission::constant::emit_void(self) + } else { + self.normalize_if_else_phi( + then_block, + else_block, + if then_reaches_merge { + Some(then_exit_block) + } else { + None + }, + if else_reaches_merge { + Some(else_exit_block) + } else { + None + }, + then_value_raw, + else_value_raw, + &pre_if_var_map, + &then_ast_for_analysis, + &else_ast_for_analysis, + &then_var_map_end, + &else_var_map_end_opt, + pre_then_var_value, + )? + }; // Hint: join result variable(s) // 1) Primary: if both branches assign to the same variable name, emit a hint for that name @@ -177,25 +242,27 @@ impl MirBuilder { } // Merge other modified variables (skip the primary assignment if any) - let skip_name = assigned_then_pre.as_deref(); - self.merge_modified_vars( - then_block, - else_block, - if then_reaches_merge { - Some(then_exit_block) - } else { - None - }, - if else_reaches_merge { - Some(else_exit_block) - } else { - None - }, - &pre_if_var_map, - &then_var_map_end, - &else_var_map_end_opt, - skip_name, - )?; + if !joinir_success { + let skip_name = assigned_then_pre.as_deref(); + self.merge_modified_vars( + then_block, + else_block, + if then_reaches_merge { + Some(then_exit_block) + } else { + None + }, + if else_reaches_merge { + Some(else_exit_block) + } else { + None + }, + &pre_if_var_map, + &then_var_map_end, + &else_var_map_end_opt, + skip_name, + )?; + } self.pop_if_merge(); // Pop merge debug region diff --git a/src/mir/join_ir/lowering/if_phi_context.rs b/src/mir/join_ir/lowering/if_phi_context.rs index c0c1b9da..f2a2e7d0 100644 --- a/src/mir/join_ir/lowering/if_phi_context.rs +++ b/src/mir/join_ir/lowering/if_phi_context.rs @@ -70,6 +70,24 @@ impl IfPhiContext { } } + /// ループ外 if 用コンテキスト作成(Phase 61-4) + /// + /// ループ外の純粋な if に対しては、carrier_names は空になる。 + /// これにより、JoinIR は純粋な Select/IfMerge パターンとして処理する。 + /// + /// # Example + /// + /// ```ignore + /// let context = IfPhiContext::pure_if(); + /// try_lower_if_to_joinir(func, block_id, debug, Some(&context)); + /// ``` + pub fn pure_if() -> Self { + Self { + in_loop_body: false, + carrier_names: BTreeSet::new(), + } + } + /// 指定された変数がループキャリアかどうか判定 /// /// # Arguments