feat(joinir): Phase 188 Pattern 1 tail call parameter binding
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 <noreply@anthropic.com>
This commit is contained in:
@ -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<ValueId>)> = 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<ValueId> = 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
|
||||
|
||||
Reference in New Issue
Block a user