From 318dceebfe1c2bb43a48499099dff4f5a7d75987 Mon Sep 17 00:00:00 2001 From: nyash-codex Date: Sat, 6 Dec 2025 01:54:47 +0900 Subject: [PATCH] fix(joinir): Pattern 4 PHI loss fix with exit_bindings and block reuse MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two root causes for Pattern 4 outputting 0 instead of 25: 1. instruction_rewriter.rs:92 - BasicBlock::new() was overwriting existing blocks that already contained PHI instructions from JoinIR Select lowering. Fixed by removing and reusing existing blocks instead of creating new ones. 2. pattern4_with_continue.rs - JoinIR exit PHI (ValueId 15) was not connected to host's sum variable, causing DCE to eliminate the PHI as "unused". Fixed by using new_with_exit_bindings() with explicit LoopExitBinding to connect k_exit's sum_exit to host's sum slot. Test result: loop_continue_pattern4.hako now correctly outputs 25. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- .../joinir/merge/instruction_rewriter.rs | 10 +++++++++- .../joinir/patterns/pattern4_with_continue.rs | 12 ++++++++++-- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/src/mir/builder/control_flow/joinir/merge/instruction_rewriter.rs b/src/mir/builder/control_flow/joinir/merge/instruction_rewriter.rs index 6c4fb621..a688ad78 100644 --- a/src/mir/builder/control_flow/joinir/merge/instruction_rewriter.rs +++ b/src/mir/builder/control_flow/joinir/merge/instruction_rewriter.rs @@ -89,7 +89,15 @@ pub(super) fn merge_and_rewrite( let new_block_id = remapper .get_block(func_name, *old_block_id) .ok_or_else(|| format!("Block {:?} not found for {}", old_block_id, func_name))?; - let mut new_block = BasicBlock::new(new_block_id); + + // Phase 195 FIX: Reuse existing block if present (preserves PHI from JoinIR Select lowering) + // ultrathink "finalizer集約案": Don't overwrite blocks with BasicBlock::new() + let mut new_block = if let Some(ref mut current_func) = builder.current_function { + current_func.blocks.remove(&new_block_id) + .unwrap_or_else(|| BasicBlock::new(new_block_id)) + } else { + BasicBlock::new(new_block_id) + }; // Phase 189 FIX: Check if this is entry function's entry block (for boundary input skipping) let is_entry_func_entry_block = diff --git a/src/mir/builder/control_flow/joinir/patterns/pattern4_with_continue.rs b/src/mir/builder/control_flow/joinir/patterns/pattern4_with_continue.rs index 30b82f39..d2ff5b50 100644 --- a/src/mir/builder/control_flow/joinir/patterns/pattern4_with_continue.rs +++ b/src/mir/builder/control_flow/joinir/patterns/pattern4_with_continue.rs @@ -182,10 +182,18 @@ impl MirBuilder { ); // Merge JoinIR blocks into current function - // Phase 195: Create and pass JoinInlineBoundary for Pattern 4 - let boundary = crate::mir::join_ir::lowering::inline_boundary::JoinInlineBoundary::new_inputs_only( + // Phase 195 FIX: Use exit_bindings to connect k_exit's sum_exit to host's sum variable + // Pattern 4: k_exit(sum_exit) returns sum_exit, so we bind ValueId(15) to host's sum + let boundary = crate::mir::join_ir::lowering::inline_boundary::JoinInlineBoundary::new_with_exit_bindings( vec![ValueId(0), ValueId(1)], // JoinIR's main() parameters (i_init, sum_init) vec![loop_var_id, sum_var_id], // Host's loop variables + vec![ + crate::mir::join_ir::lowering::inline_boundary::LoopExitBinding { + carrier_name: "sum".to_string(), + join_exit_value: ValueId(15), // k_exit's parameter (sum_exit) + host_slot: sum_var_id, // variable_map["sum"] + } + ], ); // Phase 195: Capture exit PHI result (Pattern 4 returns sum) let result_val = self.merge_joinir_mir_blocks(&mir_module, Some(&boundary), debug)?;