94 lines
4.2 KiB
Rust
94 lines
4.2 KiB
Rust
|
|
use super::{ConstValue, LoopBuilder, ValueId};
|
|||
|
|
use crate::mir::BasicBlockId;
|
|||
|
|
|
|||
|
|
/// ループ脱出の種類(箱化・共通化のための型)
|
|||
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|||
|
|
pub(super) enum LoopExitKind {
|
|||
|
|
/// break文(exit blockへジャンプ)
|
|||
|
|
Break,
|
|||
|
|
/// continue文(header blockへジャンプ)
|
|||
|
|
Continue,
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
impl<'a> LoopBuilder<'a> {
|
|||
|
|
/// Emit a jump to `target` from the current block and record predecessor metadata.
|
|||
|
|
fn jump_with_pred(&mut self, target: BasicBlockId) -> Result<(), String> {
|
|||
|
|
let cur_block = self.current_block()?;
|
|||
|
|
self.emit_jump(target)?;
|
|||
|
|
let _ = crate::mir::builder::loops::add_predecessor(self.parent_builder, target, cur_block);
|
|||
|
|
Ok(())
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// [LoopForm] 【箱化】ループ脱出の共通処理(break/continue統一化)
|
|||
|
|
///
|
|||
|
|
/// Phase 25.1o: break と continue の共通パターンを抽出し、
|
|||
|
|
/// LoopExitKind で振る舞いを切り替える統一メソッド。
|
|||
|
|
///
|
|||
|
|
/// # 処理フロー
|
|||
|
|
/// 1. 現在の変数マップをスナップショット
|
|||
|
|
/// 2. [LoopForm] スナップショット保存(Break → exit_snapshots, Continue → continue_snapshots)
|
|||
|
|
/// 3. Void を定義(戻り値用のダミー)
|
|||
|
|
/// 4. [LoopForm] ターゲットブロックへジャンプ(Break → exit, Continue → header/continue_merge)
|
|||
|
|
/// 5. 現在ブロックはジャンプで終端済みのまま維持(新しい unreachable ブロックは作らない)
|
|||
|
|
fn do_loop_exit(&mut self, kind: LoopExitKind) -> Result<ValueId, String> {
|
|||
|
|
// 1. スナップショット取得(共通処理)
|
|||
|
|
let snapshot = self.get_current_variable_map();
|
|||
|
|
let cur_block = self.current_block()?;
|
|||
|
|
|
|||
|
|
// 2. [LoopForm] exit-break path: スナップショット保存(exit PHI入力用)
|
|||
|
|
// [LoopForm] continue-backedge path: スナップショット保存(continue_merge → header)
|
|||
|
|
match kind {
|
|||
|
|
LoopExitKind::Break => {
|
|||
|
|
if std::env::var("NYASH_LOOPFORM_DEBUG").is_ok() {
|
|||
|
|
eprintln!(
|
|||
|
|
"[DEBUG/do_break] Saved snapshot from block {:?}, vars: {:?}",
|
|||
|
|
cur_block,
|
|||
|
|
snapshot.keys().collect::<Vec<_>>()
|
|||
|
|
);
|
|||
|
|
}
|
|||
|
|
self.exit_snapshots.push((cur_block, snapshot));
|
|||
|
|
}
|
|||
|
|
LoopExitKind::Continue => {
|
|||
|
|
self.block_var_maps.insert(cur_block, snapshot.clone());
|
|||
|
|
self.continue_snapshots.push((cur_block, snapshot));
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 3. 戻り値用のダミーを定義(現在ブロック内で完結させる)
|
|||
|
|
let void_id = self.new_value();
|
|||
|
|
self.emit_const(void_id, ConstValue::Void)?;
|
|||
|
|
|
|||
|
|
// 4. ターゲットブロックへジャンプ(kind別処理)
|
|||
|
|
match kind {
|
|||
|
|
LoopExitKind::Break => {
|
|||
|
|
if let Some(exit_bb) = crate::mir::builder::loops::current_exit(self.parent_builder)
|
|||
|
|
{
|
|||
|
|
self.jump_with_pred(exit_bb)?;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
LoopExitKind::Continue => {
|
|||
|
|
// 既定では header にジャンプするが、canonical continue merge を導入した場合は
|
|||
|
|
// continue_target 側を優先する。
|
|||
|
|
if let Some(target) = self.continue_target.or(self.loop_header) {
|
|||
|
|
self.jump_with_pred(target)?;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 5. 現在ブロックは jump で終端済み。新しい unreachable ブロックは作らない。
|
|||
|
|
Ok(void_id)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// Handle a `break` statement: jump to loop exit and continue in a fresh unreachable block.
|
|||
|
|
/// 【箱化】do_loop_exit() への thin wrapper
|
|||
|
|
pub(super) fn do_break(&mut self) -> Result<ValueId, String> {
|
|||
|
|
self.do_loop_exit(LoopExitKind::Break)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// Handle a `continue` statement: snapshot vars, jump to loop header, then continue in a fresh unreachable block.
|
|||
|
|
/// 【箱化】do_loop_exit() への thin wrapper
|
|||
|
|
pub(super) fn do_continue(&mut self) -> Result<ValueId, String> {
|
|||
|
|
self.do_loop_exit(LoopExitKind::Continue)
|
|||
|
|
}
|
|||
|
|
}
|