feat(joinir): Phase 61-4 loop-outside If JoinIR infrastructure
Phase 61-4 ループ外 If の JoinIR 基盤実装: 1. env フラグ追加: - HAKO_JOINIR_IF_TOPLEVEL: 本番経路有効化 - HAKO_JOINIR_IF_TOPLEVEL_DRYRUN: dry-run モード 2. IfPhiContext 拡張: - pure_if() コンストラクタ追加(ループ外 if 用) 3. if_form.rs 統合: - JoinIR 試行コード追加(dry-run対応) - フォールバック経路維持(既存PHI生成) 現状: - dry-run モード動作確認済み - 関数名ガードにより main 関数はスキップ - 本番経路は未実装(関数名ガード拡張が必要) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@ -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).
|
||||
|
||||
|
||||
@ -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,7 +135,70 @@ impl MirBuilder {
|
||||
let assigned_else_pre: Option<String> = None;
|
||||
let pre_then_var_value: Option<ValueId> = None;
|
||||
|
||||
let result_val = self.normalize_if_else_phi(
|
||||
// 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<String> = 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 {
|
||||
@ -155,7 +219,8 @@ impl MirBuilder {
|
||||
&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,6 +242,7 @@ impl MirBuilder {
|
||||
}
|
||||
|
||||
// Merge other modified variables (skip the primary assignment if any)
|
||||
if !joinir_success {
|
||||
let skip_name = assigned_then_pre.as_deref();
|
||||
self.merge_modified_vars(
|
||||
then_block,
|
||||
@ -196,6 +262,7 @@ impl MirBuilder {
|
||||
&else_var_map_end_opt,
|
||||
skip_name,
|
||||
)?;
|
||||
}
|
||||
|
||||
self.pop_if_merge();
|
||||
// Pop merge debug region
|
||||
|
||||
@ -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
|
||||
|
||||
Reference in New Issue
Block a user