feat(llvm): Phase 132 - Pattern 1 exit value parity fix + Box-First refactoring
## Phase 132: Exit PHI Value Parity Fix ### Problem Pattern 1 (Simple While) returned 0 instead of final loop variable value (3) - VM: RC: 3 ✅ (correct) - LLVM: Result: 0 ❌ (wrong) ### Root Cause (Two Layers) 1. **JoinIR/Boundary**: Missing exit_bindings → ExitLineReconnector not firing 2. **LLVM Python**: block_end_values snapshot dropping PHI values ### Fix **JoinIR** (simple_while_minimal.rs): - Jump(k_exit, [i_param]) passes exit value **Boundary** (pattern1_minimal.rs): - Added LoopExitBinding with carrier_name="i", role=LoopState - Enables ExitLineReconnector to update variable_map **LLVM** (block_lower.py): - Use predeclared_ret_phis for reliable PHI filtering - Protect builder.vmap PHIs from overwrites (SSOT principle) ### Result - ✅ VM: RC: 3 - ✅ LLVM: Result: 3 - ✅ VM/LLVM parity achieved ## Phase 132-Post: Box-First Refactoring ### Rust Side **JoinModule::require_function()** (mod.rs): - Encapsulate function search logic - 10 lines → 1 line (90% reduction) - Reusable for Pattern 2-5 ### Python Side **PhiManager Box** (phi_manager.py - new): - Centralized PHI lifecycle management - 47 lines → 8 lines (83% reduction) - SSOT: builder.vmap owns PHIs - Fail-Fast: No silent overwrites **Integration**: - LLVMBuilder: Added phi_manager - block_lower.py: Delegated to PhiManager - tagging.py: Register PHIs with manager ### Documentation **New Files**: - docs/development/architecture/exit-phi-design.md - docs/development/current/main/investigations/phase132-llvm-exit-phi-wrong-result.md - docs/development/current/main/phases/phase-132/ **Updated**: - docs/development/current/main/10-Now.md - docs/development/current/main/phase131-3-llvm-lowering-inventory.md ### Design Principles - Box-First: Logic encapsulated in classes/methods - SSOT: Single Source of Truth (builder.vmap for PHIs) - Fail-Fast: Early explicit failures, no fallbacks - Separation of Concerns: 3-layer architecture 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
@ -75,6 +75,7 @@ def setup_phi_placeholders(builder, blocks: List[Dict[str, Any]]):
|
||||
ph = ensure_phi(builder, bid0, dst0, bb0)
|
||||
# Keep a strong reference as a predeclared placeholder so
|
||||
# later ensure_phi calls during finalize re-use the same SSA node.
|
||||
# Phase 132-Post: Register PHI with PhiManager Box
|
||||
try:
|
||||
if not hasattr(builder, 'predeclared_ret_phis') or builder.predeclared_ret_phis is None:
|
||||
builder.predeclared_ret_phis = {}
|
||||
@ -82,6 +83,9 @@ def setup_phi_placeholders(builder, blocks: List[Dict[str, Any]]):
|
||||
builder.predeclared_ret_phis = {}
|
||||
try:
|
||||
builder.predeclared_ret_phis[(int(bid0), int(dst0))] = ph
|
||||
# Phase 132-Post: Box-First - register with PhiManager
|
||||
if hasattr(builder, 'phi_manager'):
|
||||
builder.phi_manager.register_phi(int(bid0), int(dst0), ph)
|
||||
if debug_mode:
|
||||
print(f"[phi_wiring/setup] Created PHI placeholder for v{dst0} in bb{bid0}")
|
||||
except Exception:
|
||||
|
||||
@ -84,6 +84,13 @@ def ensure_phi(builder, block_id: int, dst_vid: int, bb: ir.Block) -> ir.Instruc
|
||||
pass
|
||||
|
||||
ph = b.phi(builder.i64, name=f"phi_{dst_vid}")
|
||||
# Phase 132 Debug: Check if basic_block is set correctly
|
||||
import os, sys
|
||||
if os.environ.get('NYASH_PHI_ORDERING_DEBUG') == '1' or os.environ.get('NYASH_LLVM_VMAP_TRACE') == '1':
|
||||
phi_bb = getattr(ph, 'basic_block', None)
|
||||
phi_bb_name = getattr(phi_bb, 'name', None) if phi_bb is not None else None
|
||||
bb_name = getattr(bb, 'name', None)
|
||||
print(f"[phi_wiring/create] v{dst_vid} PHI created: phi.basic_block={phi_bb_name} expected={bb_name}", file=sys.stderr)
|
||||
builder.vmap[dst_vid] = ph
|
||||
trace({"phi": "ensure_create", "block": int(block_id), "dst": int(dst_vid), "after_term": block_has_terminator})
|
||||
return ph
|
||||
|
||||
Reference in New Issue
Block a user