fix(mir): conservative PHI box for If/Loop and Stage1 resolver SSA
This commit is contained in:
@ -154,9 +154,11 @@ impl<'a> LoopBuilder<'a> {
|
||||
body: Vec<ASTNode>,
|
||||
) -> Result<ValueId, String> {
|
||||
// Check feature flag for LoopForm PHI v2
|
||||
// 📦 Default to true (v2 is now stable and default)
|
||||
// Set NYASH_LOOPFORM_PHI_V2=0 to use legacy version if needed
|
||||
let use_loopform_v2 = std::env::var("NYASH_LOOPFORM_PHI_V2")
|
||||
.map(|v| v == "1" || v.to_lowercase() == "true")
|
||||
.unwrap_or(false);
|
||||
.unwrap_or(true);
|
||||
|
||||
if std::env::var("NYASH_LOOPFORM_DEBUG").is_ok() {
|
||||
eprintln!("[build_loop] use_loopform_v2={}", use_loopform_v2);
|
||||
@ -165,7 +167,8 @@ impl<'a> LoopBuilder<'a> {
|
||||
if use_loopform_v2 {
|
||||
self.build_loop_with_loopform(condition, body)
|
||||
} else {
|
||||
eprintln!("⚠️ WARNING: Using legacy loop builder! Set NYASH_LOOPFORM_PHI_V2=1");
|
||||
eprintln!("⚠️ WARNING: Using legacy loop builder! LoopForm v2 is now default.");
|
||||
eprintln!("⚠️ Legacy version may be deprecated in future releases.");
|
||||
self.build_loop_legacy(condition, body)
|
||||
}
|
||||
}
|
||||
@ -222,7 +225,10 @@ impl<'a> LoopBuilder<'a> {
|
||||
let exit_id = self.new_block();
|
||||
|
||||
// Jump from current block to preheader
|
||||
let entry_block = self.current_block()?;
|
||||
self.emit_jump(preheader_id)?;
|
||||
// 📦 Hotfix 6: Add CFG predecessor for preheader (same as legacy version)
|
||||
crate::mir::builder::loops::add_predecessor(self.parent_builder, preheader_id, entry_block)?;
|
||||
|
||||
// Initialize LoopFormBuilder with preheader and header blocks
|
||||
let mut loopform = LoopFormBuilder::new(preheader_id, header_id);
|
||||
@ -259,6 +265,8 @@ impl<'a> LoopBuilder<'a> {
|
||||
|
||||
// Pass 2: Emit preheader (copies and jump to header)
|
||||
loopform.emit_preheader(self)?;
|
||||
// 📦 Hotfix 6: Add CFG predecessor for header from preheader (same as legacy version)
|
||||
crate::mir::builder::loops::add_predecessor(self.parent_builder, header_id, preheader_id)?;
|
||||
|
||||
// Pass 3: Emit header PHIs (incomplete, only preheader edge)
|
||||
self.set_current_block(header_id)?;
|
||||
@ -301,8 +309,23 @@ impl<'a> LoopBuilder<'a> {
|
||||
}
|
||||
}
|
||||
self.emit_branch(cond_value, body_id, exit_id)?;
|
||||
// 📦 Hotfix 6: Add CFG predecessors for branch targets (Cytron et al. 1991 requirement)
|
||||
// This ensures exit_block.predecessors is populated before Exit PHI generation
|
||||
if std::env::var("NYASH_LOOPFORM_DEBUG").is_ok() {
|
||||
eprintln!("[loopform/condition] BEFORE add_predecessor: exit_id={:?}, branch_source={:?}", exit_id, branch_source_block);
|
||||
}
|
||||
crate::mir::builder::loops::add_predecessor(self.parent_builder, body_id, branch_source_block)?;
|
||||
crate::mir::builder::loops::add_predecessor(self.parent_builder, exit_id, branch_source_block)?;
|
||||
if std::env::var("NYASH_LOOPFORM_DEBUG").is_ok() {
|
||||
eprintln!("[loopform/condition] AFTER emit_branch: current_block={:?}", self.current_block()?);
|
||||
eprintln!("[loopform/condition] Added predecessors: body={:?} exit={:?} from={:?}",
|
||||
body_id, exit_id, branch_source_block);
|
||||
// Verify predecessors were added
|
||||
if let Some(ref func) = self.parent_builder.current_function {
|
||||
if let Some(exit_block) = func.blocks.get(&exit_id) {
|
||||
eprintln!("[loopform/condition] exit_block.predecessors = {:?}", exit_block.predecessors);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Lower loop body
|
||||
@ -336,6 +359,8 @@ impl<'a> LoopBuilder<'a> {
|
||||
}
|
||||
|
||||
self.emit_jump(header_id)?;
|
||||
// 📦 Hotfix 6: Add CFG predecessor for header from latch (same as legacy version)
|
||||
crate::mir::builder::loops::add_predecessor(self.parent_builder, header_id, latch_id)?;
|
||||
|
||||
// Pass 4: Seal PHIs with latch values
|
||||
loopform.seal_phis(self, actual_latch_id)?;
|
||||
@ -1256,6 +1281,19 @@ impl<'a> LoopFormOps for LoopBuilder<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
fn get_block_predecessors(&self, block: BasicBlockId) -> std::collections::HashSet<BasicBlockId> {
|
||||
// 📦 Hotfix 6: Get actual CFG predecessors for PHI validation
|
||||
if let Some(ref func) = self.parent_builder.current_function {
|
||||
if let Some(bb) = func.blocks.get(&block) {
|
||||
bb.predecessors.clone()
|
||||
} else {
|
||||
std::collections::HashSet::new() // Non-existent blocks have no predecessors
|
||||
}
|
||||
} else {
|
||||
std::collections::HashSet::new()
|
||||
}
|
||||
}
|
||||
|
||||
fn is_parameter(&self, name: &str) -> bool {
|
||||
// A parameter is a true function parameter that doesn't change across iterations
|
||||
// Pinned receivers (__pin$*$@*) are NOT parameters - they're carriers
|
||||
|
||||
Reference in New Issue
Block a user