From 2c68b04e49b3bd958753dbe182b835b4d75d6d22 Mon Sep 17 00:00:00 2001 From: nyash-codex Date: Fri, 5 Dec 2025 11:40:05 +0900 Subject: [PATCH] feat(joinir): Phase 188 Pattern 1 tail call parameter binding MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Problem: Tail call conversion (Call→Jump) was failing because: 1. Function parameters were not bound, causing "undefined value" errors 2. Instructions before Call (like BoxCall for print) were being skipped Solution: Implemented two-pass tail call conversion: - First pass: Process all instructions, detect tail calls, skip only Call itself - Second pass: Insert Copy instructions to bind call arguments to parameters Implementation: - Lines 517-609: Two-pass approach with tail_call_target tracking - Lines 588-603: Parameter binding via Copy instructions (arg → param) - Lines 566-573: Debug logging for BoxCall verification Example binding: Call(loop_step, [i_next]) → Copy { dst: param_i, src: i_next } → Jump(loop_step_entry) Status: JoinIR firing ✅, parameter binding ✅ Blocker: Non-deterministic HashMap iteration (next fix) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- src/mir/builder/control_flow.rs | 70 ++++++++++++++++++++++++++++----- 1 file changed, 60 insertions(+), 10 deletions(-) diff --git a/src/mir/builder/control_flow.rs b/src/mir/builder/control_flow.rs index 4e8540b3..3c06d701 100644 --- a/src/mir/builder/control_flow.rs +++ b/src/mir/builder/control_flow.rs @@ -514,6 +514,9 @@ impl super::MirBuilder { // Remap instructions (Phase 189: Convert inter-function Calls to control flow) let mut found_tail_call = false; + let mut tail_call_target: Option<(BasicBlockId, Vec)> = None; + + // First pass: Process all instructions, identify tail calls for inst in &old_block.instructions { // Phase 189: Skip Const String instructions that define function names if let MirInstruction::Const { dst, value } = inst { @@ -527,26 +530,30 @@ impl super::MirBuilder { } } - // Phase 189: Convert Call to Jump terminator - if let MirInstruction::Call { func, .. } = inst { + // Phase 189: Detect tail calls and save parameters + if let MirInstruction::Call { func, args, .. } = inst { if let Some(func_name) = value_to_func_name.get(func) { if let Some(&target_block) = function_entry_map.get(func_name) { + // This is a tail call - save info and skip the Call instruction itself + let remapped_args: Vec = args + .iter() + .map(|&v| value_map.get(&v).copied().unwrap_or(v)) + .collect(); + tail_call_target = Some((target_block, remapped_args)); + found_tail_call = true; + if debug { eprintln!( - "[cf_loop/joinir] Call(name='{}') → Jump terminator to {:?}", - func_name, target_block + "[cf_loop/joinir] Detected tail call to '{}' (args={:?}), will convert to Jump", + func_name, args ); } - // Set the terminator to Jump and stop processing this block - new_block.terminator = Some(MirInstruction::Jump { - target: target_block, - }); - found_tail_call = true; - break; // Don't process further instructions + continue; // Skip the Call instruction itself } } } + // Process regular instructions let remapped = Self::remap_joinir_instruction( inst, &value_map, @@ -555,8 +562,51 @@ impl super::MirBuilder { &value_to_func_name, debug, ); + + if debug { + match inst { + MirInstruction::BoxCall { .. } => { + eprintln!("[cf_loop/joinir] Adding BoxCall to block {:?}: {:?}", new_block_id, inst); + } + _ => {} + } + } + new_block.instructions.push(remapped); } + + // Second pass: Insert parameter bindings for tail calls + if let Some((target_block, args)) = tail_call_target { + if debug { + eprintln!( + "[cf_loop/joinir] Inserting param bindings for tail call to {:?}", + target_block + ); + } + + // Insert Copy instructions for parameter binding + for (i, arg_val_remapped) in args.iter().enumerate() { + let param_val_original = ValueId(i as u32); + if let Some(¶m_val_remapped) = value_map.get(¶m_val_original) { + new_block.instructions.push(MirInstruction::Copy { + dst: param_val_remapped, + src: *arg_val_remapped, + }); + + if debug { + eprintln!( + "[cf_loop/joinir] Param binding: arg {:?} → param {:?}", + arg_val_remapped, param_val_remapped + ); + } + } + } + + // Set terminator to Jump + new_block.terminator = Some(MirInstruction::Jump { + target: target_block, + }); + } new_block.instruction_spans = old_block.instruction_spans.clone(); // Remap terminator (convert Return → Jump to exit) if not already set by tail call