Span trace utilities and runner source hint

This commit is contained in:
nyash-codex
2025-11-24 14:17:02 +09:00
parent 3154903121
commit 466e636af6
106 changed files with 4597 additions and 958 deletions

View File

@ -180,11 +180,11 @@ impl BodyLocalPhiBuilder {
}
if enable_live_rescue {
if matches!(class, super::loop_var_classifier::LoopVarClass::BodyLocalInternal)
&& live_at_exit.contains(*var_name)
&& self
.inspector
.is_available_in_all(var_name, exit_preds)
if matches!(
class,
super::loop_var_classifier::LoopVarClass::BodyLocalInternal
) && live_at_exit.contains(*var_name)
&& self.inspector.is_available_in_all(var_name, exit_preds)
{
return true;
}
@ -370,7 +370,7 @@ mod tests {
&pinned,
&carrier,
&[BasicBlockId(2), BasicBlockId(5)],
&live_at_exit, // Phase 26-F-4
&live_at_exit, // Phase 26-F-4
);
// Expected: s, idx, n (ch is BodyLocalInternal → filtered out)
@ -406,8 +406,13 @@ mod tests {
// Phase 26-F-4: empty live_at_exitlive情報なし
let live_at_exit = std::collections::BTreeSet::new();
let phi_vars =
builder.filter_exit_phi_candidates(&all_vars, &pinned, &carrier, &exit_preds, &live_at_exit);
let phi_vars = builder.filter_exit_phi_candidates(
&all_vars,
&pinned,
&carrier,
&exit_preds,
&live_at_exit,
);
// Expected: s, idx (ch filtered out!)
assert_eq!(phi_vars.len(), 2);
@ -474,8 +479,13 @@ mod tests {
// Phase 26-F-4: empty live_at_exitlive情報なし
let live_at_exit = std::collections::BTreeSet::new();
let phi_vars =
builder.filter_exit_phi_candidates(&all_vars, &pinned, &[], &[BasicBlockId(5)], &live_at_exit);
let phi_vars = builder.filter_exit_phi_candidates(
&all_vars,
&pinned,
&[],
&[BasicBlockId(5)],
&live_at_exit,
);
// Only s should remain
assert_eq!(phi_vars.len(), 1);

View File

@ -27,7 +27,7 @@ impl ConservativeMerge {
/// * `then_end` - then-branch終了時の変数マップ
/// * `else_end_opt` - else-branch終了時の変数マップNoneの場合はempty else
pub fn analyze(
pre_if: &BTreeMap<String, ValueId>, // Phase 25.1: BTreeMap化
pre_if: &BTreeMap<String, ValueId>, // Phase 25.1: BTreeMap化
then_end: &BTreeMap<String, ValueId>, // Phase 25.1: BTreeMap化
else_end_opt: &Option<BTreeMap<String, ValueId>>, // Phase 25.1: BTreeMap化
) -> Self {

View File

@ -18,8 +18,8 @@ use std::collections::{BTreeMap, BTreeSet};
use super::body_local_phi_builder::BodyLocalPhiBuilder;
use super::loop_exit_liveness::{ExitLivenessProvider, LoopExitLivenessBox}; // Phase 26-F-4
use super::loop_snapshot_merge::LoopSnapshotMergeBox;
use super::phi_invariants::PhiInvariantsBox;
use super::phi_input_collector::PhiInputCollector;
use super::phi_invariants::PhiInvariantsBox;
/// Exit PHI生成専門Box
///
@ -76,8 +76,7 @@ impl ExitPhiBuilder {
/// ```
pub fn new(body_local_builder: BodyLocalPhiBuilder) -> Self {
// 環境変数で簡易 MirScan 版を opt-in できるようにする
let use_scan =
std::env::var("NYASH_EXIT_LIVE_ENABLE").ok().as_deref() == Some("1");
let use_scan = std::env::var("NYASH_EXIT_LIVE_ENABLE").ok().as_deref() == Some("1");
if use_scan {
Self::with_liveness(
body_local_builder,
@ -185,16 +184,19 @@ impl ExitPhiBuilder {
// Phase 26-F/G: ExitLivenessProvider で live_at_exit を計算MirQuery 経由)
let query = crate::mir::MirQueryBox::new(ops.mir_function());
let live_at_exit = self
.liveness_provider
.compute_live_at_exit(&query, exit_id, header_vals, exit_snapshots);
let live_at_exit = self.liveness_provider.compute_live_at_exit(
&query,
exit_id,
header_vals,
exit_snapshots,
);
let phi_vars = self.body_local_builder.filter_exit_phi_candidates(
&required_vars.iter().cloned().collect::<Vec<_>>(),
pinned_vars,
carrier_vars,
&exit_preds,
&live_at_exit, // Phase 26-F-4: live_at_exit 追加
&live_at_exit, // Phase 26-F-4: live_at_exit 追加
);
// Fail-Fast invariant共通箱経由:
@ -361,12 +363,9 @@ impl<T: crate::mir::phi_core::loopform_builder::LoopFormOps> LoopFormOps for T {
}
fn get_block_predecessors(&self, block_id: BasicBlockId) -> BTreeSet<BasicBlockId> {
crate::mir::phi_core::loopform_builder::LoopFormOps::get_block_predecessors(
self,
block_id,
)
.into_iter()
.collect()
crate::mir::phi_core::loopform_builder::LoopFormOps::get_block_predecessors(self, block_id)
.into_iter()
.collect()
}
fn block_exists(&self, block_id: BasicBlockId) -> bool {

View File

@ -181,7 +181,9 @@ impl HeaderPhiBuilder {
pub fn new() -> Self {
// Phase 27.4-B/27.4C Cleanup: JoinIR 実験フラグのチェック(ログ出力のみ、挙動変更なし)
if crate::mir::join_ir::env_flag_is_1("NYASH_JOINIR_HEADER_EXP") {
eprintln!("[HeaderPhiBuilder] JoinIR experiment flag is ON (NYASH_JOINIR_HEADER_EXP=1)");
eprintln!(
"[HeaderPhiBuilder] JoinIR experiment flag is ON (NYASH_JOINIR_HEADER_EXP=1)"
);
}
Self::default()
}

View File

@ -24,8 +24,8 @@
//! - **橋渡し**: IfPhiContext経由で最小限の情報伝達箱離婚
//! - **Fail-Fast**: 不正入力は即座にエラー
use crate::mir::{BasicBlockId, ValueId};
use crate::mir::phi_core::phi_builder_box::IfPhiContext;
use crate::mir::{BasicBlockId, ValueId};
use std::collections::BTreeMap;
/// If Body-Local Merge Box
@ -105,7 +105,7 @@ impl IfBodyLocalMergeBox {
then_end: &BTreeMap<String, ValueId>,
else_end_opt: &Option<BTreeMap<String, ValueId>>,
_reachable_preds: &[BasicBlockId],
if_context: &IfPhiContext, // Phase 26-F-3: ループ内コンテキスト
if_context: &IfPhiContext, // Phase 26-F-3: ループ内コンテキスト
) -> Vec<String> {
use std::collections::BTreeSet;
@ -117,7 +117,8 @@ impl IfBodyLocalMergeBox {
// 1. 両腕に存在する変数名を収集(決定的順序)
let then_names: BTreeSet<&String> = then_end.keys().collect();
let else_names: BTreeSet<&String> = else_end.keys().collect();
let common_names: BTreeSet<&String> = then_names.intersection(&else_names).copied().collect();
let common_names: BTreeSet<&String> =
then_names.intersection(&else_names).copied().collect();
// Phase 26-F-3: ループ内モードで片腕のみのcarrier変数も追加
let mut candidate_names_set = common_names.clone();
@ -207,7 +208,7 @@ mod tests {
&then_end,
&Some(else_end),
&[BasicBlockId(1), BasicBlockId(2)],
&default_if_context(), // Phase 26-F-3: コンテキスト追加
&default_if_context(), // Phase 26-F-3: コンテキスト追加
);
assert_eq!(candidates, vec!["x".to_string()]);
@ -228,7 +229,7 @@ mod tests {
&then_end,
&Some(else_end),
&[BasicBlockId(1), BasicBlockId(2)],
&default_if_context(), // Phase 26-F-3: コンテキスト追加
&default_if_context(), // Phase 26-F-3: コンテキスト追加
);
// 片腕のみ → BodyLocalInternal相当 → 候補なし
@ -252,7 +253,7 @@ mod tests {
&then_end,
&Some(else_end),
&[BasicBlockId(1), BasicBlockId(2)],
&default_if_context(), // Phase 26-F-3: コンテキスト追加
&default_if_context(), // Phase 26-F-3: コンテキスト追加
);
// 値が変わってない → φ不要
@ -279,7 +280,7 @@ mod tests {
&then_end,
&Some(else_end),
&[BasicBlockId(1), BasicBlockId(2)],
&loop_context(vec!["i"]), // i はキャリア変数
&loop_context(vec!["i"]), // i はキャリア変数
);
// ループ内モード: carrier変数iは片腕のみでもPHI候補に
@ -296,18 +297,18 @@ mod tests {
pre_if.insert("i".to_string(), ValueId(10));
let mut then_end = BTreeMap::new();
then_end.insert("ch".to_string(), ValueId(5)); // ch は then のみ
then_end.insert("ch".to_string(), ValueId(5)); // ch は then のみ
then_end.insert("i".to_string(), ValueId(20));
let mut else_end = BTreeMap::new();
else_end.insert("i".to_string(), ValueId(30)); // i は else にも
else_end.insert("i".to_string(), ValueId(30)); // i は else にも
let candidates = IfBodyLocalMergeBox::compute_if_merge_phi_candidates(
&pre_if,
&then_end,
&Some(else_end),
&[BasicBlockId(1), BasicBlockId(2)],
&loop_context(vec!["i"]), // i のみキャリア
&loop_context(vec!["i"]), // i のみキャリア
);
// i はキャリア → 候補に含まれる
@ -329,7 +330,7 @@ mod tests {
&then_end,
&None,
&[BasicBlockId(1)],
&default_if_context(), // Phase 26-F-3: コンテキスト追加
&default_if_context(), // Phase 26-F-3: コンテキスト追加
);
// empty else → 何も絞らない

View File

@ -201,10 +201,7 @@ impl ExitLivenessProvider for MirScanExitLiveness {
header_vals: &BTreeMap<String, ValueId>,
exit_snapshots: &[(BasicBlockId, BTreeMap<String, ValueId>)],
) -> BTreeSet<String> {
let trace = std::env::var("NYASH_EXIT_LIVENESS_TRACE")
.ok()
.as_deref()
== Some("1");
let trace = std::env::var("NYASH_EXIT_LIVENESS_TRACE").ok().as_deref() == Some("1");
// 対象ブロック集合exit と break preds
let mut targets: BTreeSet<BasicBlockId> = BTreeSet::new();
@ -325,13 +322,14 @@ mod tests {
snap2.insert("i".to_string(), ValueId(50));
snap2.insert("pname".to_string(), ValueId(60));
let exit_snapshots = vec![
(BasicBlockId(100), snap1),
(BasicBlockId(200), snap2),
];
let exit_snapshots = vec![(BasicBlockId(100), snap1), (BasicBlockId(200), snap2)];
let live_at_exit =
liveness_box.compute_live_at_exit(&query, BasicBlockId(0), &header_vals, &exit_snapshots);
let live_at_exit = liveness_box.compute_live_at_exit(
&query,
BasicBlockId(0),
&header_vals,
&exit_snapshots,
);
// Phase 1: 空の live_at_exitMIRスキャン実装待ち
assert_eq!(live_at_exit.len(), 0);
@ -345,8 +343,12 @@ mod tests {
let header_vals = BTreeMap::new();
let exit_snapshots = vec![];
let live_at_exit =
liveness_box.compute_live_at_exit(&query, BasicBlockId(0), &header_vals, &exit_snapshots);
let live_at_exit = liveness_box.compute_live_at_exit(
&query,
BasicBlockId(0),
&header_vals,
&exit_snapshots,
);
assert_eq!(live_at_exit.len(), 0);
}
@ -365,13 +367,14 @@ mod tests {
let mut snap2 = BTreeMap::new();
snap2.insert("i".to_string(), ValueId(30)); // 重複
let exit_snapshots = vec![
(BasicBlockId(100), snap1),
(BasicBlockId(200), snap2),
];
let exit_snapshots = vec![(BasicBlockId(100), snap1), (BasicBlockId(200), snap2)];
let live_at_exit =
liveness_box.compute_live_at_exit(&query, BasicBlockId(0), &header_vals, &exit_snapshots);
let live_at_exit = liveness_box.compute_live_at_exit(
&query,
BasicBlockId(0),
&header_vals,
&exit_snapshots,
);
// Phase 1: 空の live_at_exitMIRスキャン実装待ち
assert_eq!(live_at_exit.len(), 0);

View File

@ -9,7 +9,7 @@
use crate::mir::{BasicBlockId, ValueId};
use std::collections::BTreeMap; // Phase 25.1: 決定性確保
// Phase 25.1: BTreeMap → BTreeMap決定性確保・内部使用のみ
// Phase 25.1: BTreeMap → BTreeMap決定性確保・内部使用のみ
/// ループSnapshotの一元管理Box
///
@ -104,7 +104,8 @@ impl LoopSnapshotManager {
// Phase 25.1: BTreeMap → BTreeMap決定性確保・内部変換
pub fn add_exit_snapshot(&mut self, block: BasicBlockId, vars: BTreeMap<String, ValueId>) {
// Convert BTreeMap to BTreeMap for deterministic iteration
self.exit_snapshots.push((block, vars.into_iter().collect()));
self.exit_snapshots
.push((block, vars.into_iter().collect()));
}
/// Add continue snapshot
@ -120,7 +121,8 @@ impl LoopSnapshotManager {
// Phase 25.1: BTreeMap → BTreeMap決定性確保・内部変換
pub fn add_continue_snapshot(&mut self, block: BasicBlockId, vars: BTreeMap<String, ValueId>) {
// Convert BTreeMap to BTreeMap for deterministic iteration
self.continue_snapshots.push((block, vars.into_iter().collect()));
self.continue_snapshots
.push((block, vars.into_iter().collect()));
}
/// Get preheader snapshot

View File

@ -17,7 +17,7 @@
use crate::mir::{BasicBlockId, ValueId};
use std::collections::{BTreeMap, BTreeSet}; // Phase 25.1: 決定性確保
// Phase 25.1: BTreeMap → BTreeMap決定性確保・内部使用のみ
// Phase 25.1: BTreeMap → BTreeMap決定性確保・内部使用のみ
// Option C PHI bug fix: Use box-based classification
use super::local_scope_inspector::LocalScopeInspectorBox;

View File

@ -332,7 +332,7 @@ impl LoopFormBuilder {
latch_id: BasicBlockId,
continue_snapshots: &[(BasicBlockId, BTreeMap<String, ValueId>)],
_writes: &std::collections::HashSet<String>, // Step 5-1/5-2: Reserved for future optimization
header_bypass: bool, // Phase 27.4C: Header φ バイパスフラグ
header_bypass: bool, // Phase 27.4C: Header φ バイパスフラグ
) -> Result<(), String> {
let debug = std::env::var("NYASH_LOOPFORM_DEBUG").is_ok();
@ -442,8 +442,9 @@ impl LoopFormBuilder {
continue;
}
carrier.latch_value =
ops.get_variable_at_block(&carrier.name, latch_id).ok_or_else(|| {
carrier.latch_value = ops
.get_variable_at_block(&carrier.name, latch_id)
.ok_or_else(|| {
format!(
"carrier '{}' not found at latch {:?}",
carrier.name, latch_id

View File

@ -212,12 +212,8 @@ impl PhiBuilderBox {
}
// Compute modified variables (決定的順序: BTreeSet使用)
let modified_vars = self.compute_modified_names_if(
pre_snapshot,
then_end,
&else_end_opt,
if_shape,
);
let modified_vars =
self.compute_modified_names_if(pre_snapshot, then_end, &else_end_opt, if_shape);
for var_name in modified_vars {
// Conservative strategy: get values with void fallback
@ -302,10 +298,14 @@ impl PhiBuilderBox {
let else_end_owned = else_end_opt.map(|m| m.clone());
// Phase 26-F-3: IfPhiContextを取得デフォルト: ループ外)
let if_context = self.if_context.as_ref().cloned().unwrap_or_else(|| IfPhiContext {
in_loop_body: false,
loop_carrier_names: std::collections::BTreeSet::new(),
});
let if_context = self
.if_context
.as_ref()
.cloned()
.unwrap_or_else(|| IfPhiContext {
in_loop_body: false,
loop_carrier_names: std::collections::BTreeSet::new(),
});
// Phase 26-F-2/F-3: IfBodyLocalMergeBoxでif-merge専用のφ候補決定
let candidates = IfBodyLocalMergeBox::compute_if_merge_phi_candidates(
@ -313,7 +313,7 @@ impl PhiBuilderBox {
then_end,
&else_end_owned,
&reachable_preds,
&if_context, // Phase 26-F-3: コンテキスト渡し
&if_context, // Phase 26-F-3: コンテキスト渡し
);
// Debug trace