mir: LoopBuilder if-merge – generate PHIs per assigned var and only for actual predecessors; avoid bogus incoming when branch terminates

This commit is contained in:
Selfhosting Dev
2025-09-22 09:35:25 +09:00
parent 6d80338814
commit b00dc4ec37

View File

@ -549,7 +549,7 @@ impl<'a> LoopBuilder<'a> {
} }
let then_var_map_end = self.get_current_variable_map(); let then_var_map_end = self.get_current_variable_map();
// Only jump to merge if not already terminated (e.g., continue/break) // Only jump to merge if not already terminated (e.g., continue/break)
{ let then_reaches_merge = {
let cur_id = self.current_block()?; let cur_id = self.current_block()?;
let need_jump = { let need_jump = {
if let Some(ref fun_ro) = self.parent_builder.current_function { if let Some(ref fun_ro) = self.parent_builder.current_function {
@ -564,8 +564,11 @@ impl<'a> LoopBuilder<'a> {
}; };
if need_jump { if need_jump {
self.emit_jump(merge_bb)?; self.emit_jump(merge_bb)?;
true
} else {
false
} }
} };
// else // else
self.set_current_block(else_bb)?; self.set_current_block(else_bb)?;
@ -593,7 +596,7 @@ impl<'a> LoopBuilder<'a> {
} }
else_var_map_end_opt = Some(self.get_current_variable_map()); else_var_map_end_opt = Some(self.get_current_variable_map());
} }
{ let else_reaches_merge = {
let cur_id = self.current_block()?; let cur_id = self.current_block()?;
let need_jump = { let need_jump = {
if let Some(ref fun_ro) = self.parent_builder.current_function { if let Some(ref fun_ro) = self.parent_builder.current_function {
@ -608,8 +611,11 @@ impl<'a> LoopBuilder<'a> {
}; };
if need_jump { if need_jump {
self.emit_jump(merge_bb)?; self.emit_jump(merge_bb)?;
true
} else {
false
} }
} };
// Continue at merge // Continue at merge
self.set_current_block(merge_bb)?; self.set_current_block(merge_bb)?;
@ -657,16 +663,31 @@ impl<'a> LoopBuilder<'a> {
.or_else(|| pre_then_var_value.get(&var_name).copied()); .or_else(|| pre_then_var_value.get(&var_name).copied());
if let (Some(tv), Some(ev)) = (then_val, else_val) { if let (Some(tv), Some(ev)) = (then_val, else_val) {
// Build incoming list only for predecessors that actually reach merge
let mut incomings: Vec<(BasicBlockId, ValueId)> = Vec::new();
if then_reaches_merge { incomings.push((then_bb, tv)); }
if else_reaches_merge { incomings.push((else_bb, ev)); }
match incomings.len() {
0 => { /* neither branch reaches merge: nothing to bind */ }
1 => {
// Single predecessor reaching merge: no PHI needed
let (_pred, v) = incomings[0];
self.parent_builder.variable_map.insert(var_name, v);
}
_ => {
let phi_id = self.new_value(); let phi_id = self.new_value();
if self.no_phi_mode { if self.no_phi_mode {
self.parent_builder.insert_edge_copy(then_bb, phi_id, tv)?; for (pred, v) in incomings.iter().copied() {
self.parent_builder.insert_edge_copy(else_bb, phi_id, ev)?; self.parent_builder.insert_edge_copy(pred, phi_id, v)?;
}
} else { } else {
self.emit_phi_at_block_start(merge_bb, phi_id, vec![(then_bb, tv), (else_bb, ev)])?; self.emit_phi_at_block_start(merge_bb, phi_id, incomings)?;
} }
self.parent_builder.variable_map.insert(var_name, phi_id); self.parent_builder.variable_map.insert(var_name, phi_id);
} }
} }
}
}
let void_id = self.new_value(); let void_id = self.new_value();
self.emit_const(void_id, ConstValue::Void)?; self.emit_const(void_id, ConstValue::Void)?;
Ok(void_id) Ok(void_id)