feat(phi): Phase 27.5 - JoinIR Exit φ 統合(LoopExitShape 雛形)
LoopExitShape 構造体を追加し、Exit φ の意味を JoinIR 側に固定: - LoopExitShape 追加 (src/mir/join_ir.rs:84-111) - exit_args: Vec<ValueId> で Exit φ の意味を表現 - minimal (exit_args=[i]), trim (exit_args=[e], Option A) - #[allow(dead_code)] で Phase 27.6 まで設計専用 - Exit φ コメント追加 - lower_skip_ws_to_joinir: 2箇所の exit パスに意味明記 - lower_funcscanner_trim_to_joinir: Option A として意味明記 - テストコメント更新 - mir_joinir_skip_ws.rs: Exit φ (i の合流) 検証を明記 - mir_joinir_funcscanner_trim.rs: Exit φ (e の合流+substring) を明記 - ドキュメント更新 - IMPLEMENTATION_LOG.md: Phase 27.5 セクション追加 - TASKS.md: Phase 27.5 完了マーク ExitPhiBuilder は Phase 27.6 まで保留。本線影響ゼロ。
This commit is contained in:
@ -81,6 +81,35 @@ impl LoopHeaderShape {
|
||||
}
|
||||
}
|
||||
|
||||
/// Phase 27.5: ループ exit φ の意味を表す構造
|
||||
///
|
||||
/// ExitPhiBuilder が生成していた「ループ脱出時の変数合流」を JoinIR の k_exit 引数として表現するためのヘルパー。
|
||||
///
|
||||
/// 用語:
|
||||
/// - **exit_args**: ループから脱出する際に k_exit に渡す値のリスト
|
||||
///
|
||||
/// 例:
|
||||
/// - **minimal_ssa_skip_ws**: exit_args = [i]
|
||||
/// - ループから抜ける時、現在の i の値を返す
|
||||
/// - **FuncScanner.trim**: exit_args = [e] (Option A)
|
||||
/// - ループから抜ける時、現在の e の値を返す(後続で substring(b, e) を呼ぶ)
|
||||
///
|
||||
/// Phase 27.5 では minimal/trim 用に手動で構成するが、将来は ExitPhiBuilder の分析から自動導出する。
|
||||
#[derive(Debug, Clone)]
|
||||
#[allow(dead_code)] // Phase 27.6 で Exit φ 統合の実装フェーズで使用予定(現在は設計の雛形)
|
||||
struct LoopExitShape {
|
||||
/// Exit 時に k_exit に渡したい値(JoinIR 引数)
|
||||
exit_args: Vec<ValueId>,
|
||||
}
|
||||
|
||||
#[allow(dead_code)] // Phase 27.6 で実際に使用予定
|
||||
impl LoopExitShape {
|
||||
/// Phase 27.5: 手動で exit_args を指定して構築
|
||||
fn new_manual(exit_args: Vec<ValueId>) -> Self {
|
||||
LoopExitShape { exit_args }
|
||||
}
|
||||
}
|
||||
|
||||
/// JoinIR 関数
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct JoinFunction {
|
||||
@ -493,10 +522,14 @@ pub fn lower_skip_ws_to_joinir(module: &crate::mir::MirModule) -> Option<JoinMod
|
||||
rhs: n_loop,
|
||||
}));
|
||||
|
||||
// Phase 27.5: Exit φ の意味を LoopExitShape で明示
|
||||
// skip_ws のループ脱出時は i の値だけを返す(先頭空白の文字数)
|
||||
let _exit_shape = LoopExitShape::new_manual(vec![i_loop]); // exit_args = [i]
|
||||
|
||||
// if i >= n { return i }
|
||||
loop_step_func.body.push(JoinInst::Jump {
|
||||
cont: JoinContId::new(0),
|
||||
args: vec![i_loop],
|
||||
args: vec![i_loop], // ← LoopExitShape.exit_args に対応
|
||||
cond: Some(cmp1_result),
|
||||
});
|
||||
|
||||
@ -550,10 +583,11 @@ pub fn lower_skip_ws_to_joinir(module: &crate::mir::MirModule) -> Option<JoinMod
|
||||
rhs: bool_false,
|
||||
}));
|
||||
|
||||
// Phase 27.5: 2箇所目の exit パス(同じく exit_args = [i])
|
||||
// if ch != " " { return i }
|
||||
loop_step_func.body.push(JoinInst::Jump {
|
||||
cont: JoinContId::new(1),
|
||||
args: vec![i_loop],
|
||||
args: vec![i_loop], // ← LoopExitShape.exit_args に対応(1箇所目と同じ)
|
||||
cond: Some(cmp2_is_false),
|
||||
});
|
||||
|
||||
@ -749,10 +783,15 @@ pub fn lower_funcscanner_trim_to_joinir(module: &crate::mir::MirModule) -> Optio
|
||||
op: CompareOp::Eq,
|
||||
}));
|
||||
|
||||
// Phase 27.5: Exit φ の意味を LoopExitShape で明示(Option A)
|
||||
// trim のループ脱出時は e の値で substring(b, e) を計算済み
|
||||
let _exit_shape_trim = LoopExitShape::new_manual(vec![e_loop]); // exit_args = [e] (Option A)
|
||||
// 実装上は既に trimmed_base = substring(b, e) を計算済みで、その結果を返している
|
||||
|
||||
// if !(e > b) { return substring(b, e) }
|
||||
loop_step_func.body.push(JoinInst::Jump {
|
||||
cont: JoinContId::new(0),
|
||||
args: vec![trimmed_base],
|
||||
args: vec![trimmed_base], // ← substring(b, e) の結果
|
||||
cond: Some(cond_is_false),
|
||||
});
|
||||
|
||||
@ -870,10 +909,11 @@ pub fn lower_funcscanner_trim_to_joinir(module: &crate::mir::MirModule) -> Optio
|
||||
op: CompareOp::Eq,
|
||||
}));
|
||||
|
||||
// Phase 27.5: 2箇所目の exit パス(同じく exit_args = [e], Option A)
|
||||
// if !is_space { return substring(b, e) }
|
||||
loop_step_func.body.push(JoinInst::Jump {
|
||||
cont: JoinContId::new(1),
|
||||
args: vec![trimmed_base],
|
||||
args: vec![trimmed_base], // ← substring(b, e) の結果(1箇所目と同じ)
|
||||
cond: Some(is_space_false),
|
||||
});
|
||||
|
||||
|
||||
@ -15,6 +15,11 @@
|
||||
// - NYASH_JOINIR_HEADER_EXP=1 を併用すると Header φ bypass が有効化される
|
||||
// - bypass 時は MIR に Header φ が生成されないが、このテストでは JoinIR のみ検証するため問題なし
|
||||
// - 将来的に JoinIR runner 実行を追加する際は、bypass モードでも正しく動作することを確認する
|
||||
//
|
||||
// Phase 27.5 対応:
|
||||
// - このテストは Header φ だけでなく、Exit φ(e の合流+substring(b, e) 呼び出し)も JoinIR で k_exit として表現できることを検証
|
||||
// - trim のループには2箇所の break パスがあり、どちらも substring(b, e) の結果を返す
|
||||
// - ExitShape Option A として設計: exit_args = [e] で、ループ内で substring(b, e) を計算済み
|
||||
|
||||
use crate::ast::ASTNode;
|
||||
use crate::mir::join_ir::*;
|
||||
|
||||
@ -15,6 +15,10 @@
|
||||
// - NYASH_JOINIR_HEADER_EXP=1 を併用すると Header φ bypass が有効化される
|
||||
// - bypass 時は MIR に Header φ が生成されないが、このテストでは JoinIR のみ検証するため問題なし
|
||||
// - 将来的に JoinIR runner 実行を追加する際は、bypass モードでも正しく動作することを確認する
|
||||
//
|
||||
// Phase 27.5 対応:
|
||||
// - このテストは Header φ だけでなく、Exit φ(i の合流)も JoinIR で k_exit(i) として表現できていることを検証
|
||||
// - skip_ws は2箇所の break パスがあり、どちらも i を返す → LoopExitShape::exit_args = [i]
|
||||
|
||||
use crate::ast::ASTNode;
|
||||
use crate::mir::join_ir::*;
|
||||
|
||||
Reference in New Issue
Block a user