bridge(loop): exit PHI を SSOT へ統一(break/continue スナップショットの stack 化)+ ループ比較スモーク(bridge)追加\n\n- lowering.rs: ループ用 break/continue スナップショットを thread-local stack で管理(push/pop/record)\n- loop_.rs: continue/break スナップを取り込み、seal_incomplete_phis_with・build_exit_phis_with に委譲\n- smokes: bridge_loop_sum/break/continue を opt-in 追加(SMOKES_ENABLE_LOOP_BRIDGE=1)

This commit is contained in:
nyash-codex
2025-11-01 16:56:26 +09:00
parent 5e07e03dd5
commit 64d7003249
4 changed files with 143 additions and 5 deletions

View File

@ -4,6 +4,7 @@ use crate::mir::{
MirPrinter, MirType, ValueId,
};
use std::collections::HashMap;
use std::cell::RefCell;
// Split out merge/new_block helpers for readability (no behavior change)
mod merge;
@ -23,6 +24,41 @@ pub(super) struct LoopContext {
pub(super) exit_bb: BasicBlockId,
}
// Snapshot stacks for loop break/continue (per-nested-loop frame)
thread_local! {
static EXIT_SNAPSHOT_STACK: RefCell<Vec<Vec<(BasicBlockId, HashMap<String, ValueId>)>>> = RefCell::new(Vec::new());
static CONT_SNAPSHOT_STACK: RefCell<Vec<Vec<(BasicBlockId, HashMap<String, ValueId>)>>> = RefCell::new(Vec::new());
}
pub(super) fn push_loop_snapshot_frames() {
EXIT_SNAPSHOT_STACK.with(|s| s.borrow_mut().push(Vec::new()));
CONT_SNAPSHOT_STACK.with(|s| s.borrow_mut().push(Vec::new()));
}
pub(super) fn pop_exit_snapshots() -> Vec<(BasicBlockId, HashMap<String, ValueId>)> {
EXIT_SNAPSHOT_STACK.with(|s| s.borrow_mut().pop().unwrap_or_default())
}
pub(super) fn pop_continue_snapshots() -> Vec<(BasicBlockId, HashMap<String, ValueId>)> {
CONT_SNAPSHOT_STACK.with(|s| s.borrow_mut().pop().unwrap_or_default())
}
fn record_exit_snapshot(cur_bb: BasicBlockId, vars: &HashMap<String, ValueId>) {
EXIT_SNAPSHOT_STACK.with(|s| {
if let Some(top) = s.borrow_mut().last_mut() {
top.push((cur_bb, vars.clone()));
}
});
}
fn record_continue_snapshot(cur_bb: BasicBlockId, vars: &HashMap<String, ValueId>) {
CONT_SNAPSHOT_STACK.with(|s| {
if let Some(top) = s.borrow_mut().last_mut() {
top.push((cur_bb, vars.clone()));
}
});
}
#[derive(Clone)]
pub(super) struct BridgeEnv {
pub(super) throw_enabled: bool,
@ -128,12 +164,16 @@ pub(super) fn lower_stmt_with_vars(
}
StmtV0::Break => {
if let Some(ctx) = loop_stack.last().copied() {
// snapshot variables at break
record_exit_snapshot(cur_bb, vars);
lower_break_stmt(f, cur_bb, ctx.exit_bb);
}
Ok(cur_bb)
}
StmtV0::Continue => {
if let Some(ctx) = loop_stack.last().copied() {
// snapshot variables at continue
record_continue_snapshot(cur_bb, vars);
lower_continue_stmt(f, cur_bb, ctx.cond_bb);
}
Ok(cur_bb)

View File

@ -30,7 +30,7 @@ pub(super) fn lower_loop_stmt(
}
}
// 3) LoopPhiOps アダプタ
// 3) LoopPhiOps アダプタ(準備用: preheader seed 専用)
struct Ops<'a> {
f: &'a mut MirFunction,
vars: &'a mut HashMap<String, ValueId>,
@ -81,6 +81,8 @@ pub(super) fn lower_loop_stmt(
let mut incomplete = crate::mir::phi_core::loop_phi::prepare_loop_variables_with(
&mut ops, cond_bb, cur_bb, &base_vars,
)?;
// Header snapshot for exit PHIs
let header_vars_snapshot = ops.vars.clone();
let (cval, _cend) = super::expr::lower_expr_with_vars(env, ops.f, cond_bb, cond, ops.vars)?;
if let Some(bb) = ops.f.get_block_mut(cond_bb) {
@ -91,12 +93,19 @@ pub(super) fn lower_loop_stmt(
});
}
let mut body_vars = ops.vars.clone();
// open snapshot frames for nested break/continue
super::push_loop_snapshot_frames();
loop_stack.push(LoopContext { cond_bb, exit_bb });
let bend_res = lower_stmt_list_with_vars(ops.f, body_bb, body, &mut body_vars, loop_stack, env);
loop_stack.pop();
let bend = bend_res?;
// latchbody末尾スナップショット
block_var_maps.insert(bend, body_vars.clone());
// collect snapshots for this loop level
let continue_snaps = super::pop_continue_snapshots();
let exit_snaps = super::pop_exit_snapshots();
// latchbody末尾スナップショットを別マップに構築
let mut block_var_maps2: HashMap<BasicBlockId, HashMap<String, ValueId>> = HashMap::new();
block_var_maps2.insert(cur_bb, base_vars.clone());
block_var_maps2.insert(bend, body_vars.clone());
if let Some(bb) = ops.f.get_block_mut(bend) {
if !bb.is_terminated() {
bb.set_terminator(MirInstruction::Jump { target: cond_bb });
@ -110,14 +119,23 @@ pub(super) fn lower_loop_stmt(
);
if backedge_to_cond {
// 5) header の不完全PHIを完成latch + continue スナップショット集約)
let continue_snaps: Vec<(BasicBlockId, HashMap<String, ValueId>)> = Vec::new();
let mut ops_seal = Ops { f: ops.f, vars: ops.vars, block_var_maps: &block_var_maps2 };
crate::mir::phi_core::loop_phi::seal_incomplete_phis_with(
&mut ops,
&mut ops_seal,
cond_bb,
bend,
std::mem::take(&mut incomplete),
&continue_snaps,
)?;
}
// 6) exit PHIsbreakの合流 + headerからのフォールスルー
let mut ops_exit = Ops { f: ops.f, vars: ops.vars, block_var_maps: &block_var_maps2 };
crate::mir::phi_core::loop_phi::build_exit_phis_with(
&mut ops_exit,
cond_bb,
exit_bb,
&header_vars_snapshot,
&exit_snaps,
)?;
Ok(exit_bb)
}