feat(joinir): Phase 33-16 Loop Header PHI SSOT with TailCallKind refactoring

## Problem
- joinir_min_loop.hako returned 0 instead of expected 2
- Entry block's tail call was redirected to itself (bb4 → bb4 self-loop)
- JoinIR function parameters lack SSA definition when inlined

## Solution
- Distinguish entry calls from back edges using TailCallKind enum
- Entry block (LoopEntry) stays at target, back edges redirect to header PHI
- Added explicit classification: LoopEntry, BackEdge, ExitJump

## Key Changes
- instruction_rewriter.rs: TailCallKind enum + classify_tail_call()
- Renamed is_entry_func_entry_block → is_loop_entry_point (clearer intent)
- loop_header_phi_builder.rs: New module for header PHI generation
- joinir_inline_boundary_injector.rs: Skip loop var Copy when header PHI handles it

## Verified
- joinir_min_loop.hako: returns 2 
- NYASH_SSA_UNDEF_DEBUG: no undefined errors 

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
nyash-codex
2025-12-07 12:01:54 +09:00
parent a09ce0cbff
commit 287ceca18d
8 changed files with 676 additions and 53 deletions

View File

@ -389,6 +389,7 @@ mod tests {
condition_inputs: vec![], // Phase 171: Add missing field
condition_bindings: vec![], // Phase 171-fix: Add missing field
expr_result: None, // Phase 33-14: Add missing field
loop_var_name: None, // Phase 33-16: Add missing field
};
builder.apply_to_boundary(&mut boundary)

View File

@ -197,6 +197,7 @@ impl MirBuilder {
boundary.condition_bindings = condition_bindings;
boundary.exit_bindings = exit_bindings.clone();
boundary.expr_result = fragment_meta.expr_result; // Phase 33-14: Pass expr_result to merger
boundary.loop_var_name = Some(loop_var_name.clone()); // Phase 33-16: For LoopHeaderPhiBuilder
// Phase 189: Capture exit PHI result (now used for reconnect)
let _ = self.merge_joinir_mir_blocks(&mir_module, Some(&boundary), debug)?;