## Problem `block_end_values` used block ID only as key, causing collisions when multiple functions share the same block IDs (e.g., bb0 in both condition_fn and main). ## Root Cause - condition_fn's bb0 → block_end_values[0] - main's bb0 → block_end_values[0] (OVERWRITES!) - PHI resolution gets wrong snapshot → dominance error ## Solution (Box-First principle) Change key from `int` to `Tuple[str, int]` (func_name, block_id): ```python # Before block_end_values: Dict[int, Dict[int, ir.Value]] # After block_end_values: Dict[Tuple[str, int], Dict[int, ir.Value]] ``` ## Files Modified (Python - 6 files) 1. `llvm_builder.py` - Type annotation update 2. `function_lower.py` - Pass func_name to lower_blocks 3. `block_lower.py` - Use tuple keys for snapshot save/load 4. `resolver.py` - Add func_name parameter to resolve_incoming 5. `wiring.py` - Thread func_name through PHI wiring 6. `phi_manager.py` - Debug traces ## Files Modified (Rust - cleanup) - Removed deprecated `loop_to_join.rs` (297 lines deleted) - Updated pattern lowerers for cleaner exit handling - Added lifecycle management improvements ## Verification - ✅ Pattern 1: VM RC: 3, LLVM Result: 3 (no regression) - ⚠️ Case C: Still has dominance error (separate root cause) - Needs additional scope fixes (phi_manager, resolver caches) ## Design Principles - **Box-First**: Each function is an isolated Box with scoped state - **SSOT**: (func_name, block_id) uniquely identifies block snapshots - **Fail-Fast**: No cross-function state contamination ## Known Issues (Phase 132-P1) Other function-local state needs same treatment: - phi_manager.predeclared - resolver caches (i64_cache, ptr_cache, etc.) - builder._jump_only_blocks ## Documentation - docs/development/current/main/investigations/phase132-p0-case-c-root-cause.md - docs/development/current/main/investigations/phase132-p0-tuple-key-implementation.md 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Investigations Folder
This folder contains investigation notes and analysis for debugging sessions.
Active Investigations
Phase 131-12: LLVM Wrong Result (Case C)
Status: ✅ Root cause identified Problem: LLVM backend returns wrong results for loop exit values Root Cause: vmap object identity mismatch between Pass A and Pass C
Key Documents:
- phase131-12-case-c-llvm-wrong-result.md - Initial investigation scope
- phase131-12-p1-vmap-identity-analysis.md - Detailed trace analysis
- phase131-12-p1-trace-summary.md - Executive summary with fix recommendations
Quick Summary:
- Bug: Pass A deletes
_current_vmapbefore Pass C runs - Impact: Terminators use wrong vmap object, missing all Pass A writes
- Fix: Store vmap_cur in deferred_terminators tuple (Option 3)
Next Steps:
- Implement Option 3 fix in block_lower.py
- Add Fail-Fast check in instruction_lower.py
- Verify with NYASH_LLVM_VMAP_TRACE=1
- Run full test suite
Trace Environment Variables
Phase 131-12-P1 Traces
NYASH_LLVM_VMAP_TRACE=1 # Object identity and vmap keys tracing
NYASH_LLVM_USE_HARNESS=1 # Enable llvmlite harness
NYASH_LLVM_DUMP_IR=<path> # Save LLVM IR to file
Investigation Workflow
- Scope - Define problem and test case (phase131-12-case-c-*.md)
- Trace - Add instrumentation and collect data (phase131-12-p1-vmap-identity-*.md)
- Analysis - Identify root cause with evidence (phase131-12-p1-trace-summary.md)
- Fix - Implement solution with validation
- Document - Update investigation notes with results
Archive
Completed investigations are kept for reference and pattern recognition.