fix(joinir): Phase 287 P2 - Pattern6 nested loop latch overwrite fix
Fix infinite loop in Pattern6 (nested loop minimal) caused by main→loop_step overwriting k_inner_exit→loop_step latch values. Root cause: JoinIR main entry block was incorrectly treated as BackEdge, causing it to overwrite the correct latch incoming values set by the true back edge (k_inner_exit → loop_step). Solution: - Restrict latch recording to TailCallKind::BackEdge only - Treat only MAIN's entry block as entry-like (not loop_step's entry block) - Add debug_assert! to detect double latch set in future Refactoring: - Extract latch recording to latch_incoming_recorder module (SSOT) - Add boundary.loop_header_func_name for explicit header identification - Strengthen tail_call_classifier with is_source_entry_like parameter Tests: apps/tests/phase1883_nested_minimal.hako → RC:9 (was infinite loop) Smoke: 154/154 PASS, no regressions 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
@ -217,7 +217,7 @@ pub(in crate::mir::builder) fn merge_joinir_mir_blocks(
|
||||
"[cf_loop/joinir] Boundary join_inputs={:?} host_inputs={:?}",
|
||||
boundary.join_inputs, boundary.host_inputs
|
||||
),
|
||||
true,
|
||||
verbose,
|
||||
);
|
||||
trace.stderr_if(
|
||||
&format!(
|
||||
@ -225,7 +225,7 @@ pub(in crate::mir::builder) fn merge_joinir_mir_blocks(
|
||||
boundary.exit_bindings.len(),
|
||||
exit_summary.join(", ")
|
||||
),
|
||||
true,
|
||||
verbose,
|
||||
);
|
||||
if !cond_summary.is_empty() {
|
||||
trace.stderr_if(
|
||||
@ -234,7 +234,7 @@ pub(in crate::mir::builder) fn merge_joinir_mir_blocks(
|
||||
cond_summary.len(),
|
||||
cond_summary.join(", ")
|
||||
),
|
||||
true,
|
||||
verbose,
|
||||
);
|
||||
}
|
||||
if let Some(ci) = &boundary.carrier_info {
|
||||
@ -244,11 +244,11 @@ pub(in crate::mir::builder) fn merge_joinir_mir_blocks(
|
||||
"[cf_loop/joinir] Boundary carrier_info: loop_var='{}', carriers={:?}",
|
||||
ci.loop_var_name, carriers
|
||||
),
|
||||
true,
|
||||
verbose,
|
||||
);
|
||||
}
|
||||
} else {
|
||||
trace.stderr_if("[cf_loop/joinir] No boundary provided", true);
|
||||
trace.stderr_if("[cf_loop/joinir] No boundary provided", verbose);
|
||||
}
|
||||
}
|
||||
|
||||
@ -364,18 +364,34 @@ pub(in crate::mir::builder) fn merge_joinir_mir_blocks(
|
||||
let (mut loop_header_phi_info, merge_entry_block) = if let Some(boundary) = boundary {
|
||||
if let Some(loop_var_name) = &boundary.loop_var_name {
|
||||
// Get loop_step function for PHI placement (the actual loop header)
|
||||
let (loop_step_func_name, loop_step_func) = mir_module
|
||||
.functions
|
||||
.iter()
|
||||
.find(|(name, _)| {
|
||||
let is_continuation = boundary.continuation_func_ids.contains(*name);
|
||||
let is_main = *name == crate::mir::join_ir::lowering::canonical_names::MAIN;
|
||||
!is_continuation && !is_main
|
||||
let loop_step_func_name = boundary
|
||||
.loop_header_func_name
|
||||
.as_deref()
|
||||
.or_else(|| {
|
||||
mir_module
|
||||
.functions
|
||||
.iter()
|
||||
.find(|(name, _)| {
|
||||
let is_continuation = boundary.continuation_func_ids.contains(*name);
|
||||
let is_main =
|
||||
*name == crate::mir::join_ir::lowering::canonical_names::MAIN;
|
||||
!is_continuation && !is_main
|
||||
})
|
||||
.map(|(name, _)| name.as_str())
|
||||
})
|
||||
.or_else(|| mir_module.functions.iter().next())
|
||||
.map(|(name, func)| (name.as_str(), func))
|
||||
.or_else(|| mir_module.functions.keys().next().map(|s| s.as_str()))
|
||||
.ok_or("JoinIR module has no functions (Phase 201-A)")?;
|
||||
|
||||
let loop_step_func = mir_module
|
||||
.functions
|
||||
.get(loop_step_func_name)
|
||||
.ok_or_else(|| {
|
||||
format!(
|
||||
"loop_header_func_name '{}' not found in JoinIR module (Phase 287 P2)",
|
||||
loop_step_func_name
|
||||
)
|
||||
})?;
|
||||
|
||||
// Phase 256.7-fix: Determine merge_entry_block
|
||||
// When main has condition_bindings as params, we enter through main first
|
||||
// (for boundary Copies), then main's tail call jumps to loop_step.
|
||||
@ -479,7 +495,7 @@ pub(in crate::mir::builder) fn merge_joinir_mir_blocks(
|
||||
"[cf_loop/joinir] Phase 256.7-fix: merge_entry_func='{}', merge_entry_block={:?}, loop_header_block={:?}",
|
||||
entry_func_name, entry_block_remapped, loop_header_block
|
||||
),
|
||||
true, // Always log for debugging
|
||||
debug,
|
||||
);
|
||||
trace.stderr_if(
|
||||
&format!(
|
||||
|
||||
Reference in New Issue
Block a user