fix(mir): conservative PHI box for If/Loop and Stage1 resolver SSA

This commit is contained in:
nyash-codex
2025-11-18 09:26:39 +09:00
parent fa087eeeea
commit 8b37e9711d
6 changed files with 181 additions and 19 deletions

View File

@ -331,8 +331,15 @@ impl LoopFormBuilder {
.push((branch_source_block, carrier.header_phi));
}
// 📦 Hotfix 6: Get actual CFG predecessors for exit block
let exit_preds = ops.get_block_predecessors(exit_id);
if debug {
eprintln!("[DEBUG/exit_phi] Exit block predecessors: {:?}", exit_preds);
}
// Add break snapshot values
// 📦 Hotfix 2: Skip non-existent blocks (幽霊ブロック対策)
// 📦 Hotfix 6: Skip blocks not in CFG predecessors (unreachable continuation対策)
for (block_id, snapshot) in exit_snapshots {
// Validate block existence before adding to PHI inputs
if !ops.block_exists(*block_id) {
@ -342,6 +349,15 @@ impl LoopFormBuilder {
continue; // Skip ghost blocks
}
// Hotfix 6: Skip blocks not in actual CFG predecessors
// This catches unreachable continuation blocks created after break/continue
if !exit_preds.contains(block_id) {
if debug {
eprintln!("[DEBUG/exit_phi] ⚠️ Skipping block {:?} (not in CFG predecessors)", block_id);
}
continue; // Skip blocks not actually branching to exit
}
for (var_name, &value) in snapshot {
all_vars
.entry(var_name.clone())
@ -409,6 +425,11 @@ pub trait LoopFormOps {
/// Used to skip non-existent blocks when building exit PHIs.
fn block_exists(&self, block: BasicBlockId) -> bool;
/// 📦 Get actual CFG predecessors for a block (Hotfix 6: PHI input validation)
/// Returns the set of blocks that actually branch to this block in the CFG.
/// Used to validate exit PHI inputs against actual control flow.
fn get_block_predecessors(&self, block: BasicBlockId) -> std::collections::HashSet<BasicBlockId>;
/// Check if a variable is a function parameter
fn is_parameter(&self, name: &str) -> bool;
@ -520,6 +541,11 @@ mod tests {
true
}
fn get_block_predecessors(&self, _block: BasicBlockId) -> std::collections::HashSet<BasicBlockId> {
// MockOps: return empty set (no CFG in test)
std::collections::HashSet::new()
}
fn is_parameter(&self, name: &str) -> bool {
self.params.iter().any(|p| p == name)
}