## 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>
6.3 KiB
6.3 KiB
Exit PHI Design - Phase 132 Architecture
Overview
Phase 132 で完成した Exit PHI アーキテクチャの責務分離設計。
Three-Layer Responsibility Model
Layer 1: JoinIR (Frontend - データ生成層)
責務: ループ脱出時の変数バインディング情報を生成
実装箇所: src/mir/join_ir/lowering/inline_boundary/
主要コンポーネント:
LoopExitBinding: ループ脱出時の変数バインディング構造pub struct LoopExitBinding { pub carrier_name: String, // 変数名 (e.g., "i") pub join_exit_value: ValueId, // JoinIR k_exit 関数の引数 pub host_slot: ValueId, // Host MIR の PHI dst }
データフロー:
Pattern 1 Minimal:
loop_step → Jump(k_exit, [i_param]) → exit_bindings = [LoopExitBinding { "i", i_param, host_slot }]
Phase 132 貢献:
exit_bindingsフィールド追加(JoinInlineBoundary構造体)- Pattern 1-5 各パターンで exit binding 生成ロジック実装
Layer 2: Boundary (Middleware - 接続実行層)
責務: JoinIR の exit_bindings を使って Host MIR に Exit PHI を接続
実装箇所: src/mir/builder/control_flow/joinir/merge/
主要コンポーネント:
ExitLineReconnector: Exit PHI 接続 Box (Phase 33-10 で箱化)impl ExitLineReconnector { fn connect_exit_line( &self, boundary: &JoinInlineBoundary, exit_block_id: BasicBlockId, exit_predecessor: BasicBlockId, builder: &mut Builder, ) -> Result<(), String> }
処理フロー:
exit_bindingsをイテレート- 各 binding について:
host_slot(PHI dst) に対して(exit_predecessor, join_exit_value)を incoming として追加
Phase 132 貢献:
exit_bindingsを読み取る発火ロジック実装- Phase 131 の metadata 参照ロジックを完全削除(SSOT化)
Layer 3: LLVM Backend (Execution - PHI保護層)
責務: builder.vmap 内の PHI を SSOT として保護・管理
実装箇所: src/llvm_py/
主要コンポーネント (Phase 132-Post):
PhiManagerBox: PHI ライフサイクル管理class PhiManager: def register_phi(bid: int, vid: int, phi_value) def is_phi_owned(bid: int, vid: int) -> bool def filter_vmap_preserve_phis(vmap: dict, target_bid: int) -> dict def sync_protect_phis(target_vmap: dict, source_vmap: dict)
SSOT Principle:
builder.vmapの PHI は Single Source of Truth- PHI は絶対に上書きしない
- ブロック間で PHI 所有権を明確に管理
Phase 132 貢献:
predeclared_ret_phisdict による PHI ownership tracking- vmap filtering: ブロック外の PHI を除外
- sync protection: 既存 PHI を上書きしない
Phase 132-Post 貢献 (Box-First Refactoring):
PhiManagerBox 化で PHI 管理ロジック集約filter_vmap_preserve_phis(): PHI フィルタリングをカプセル化sync_protect_phis(): PHI 保護ロジックをカプセル化
Data Flow Example (Pattern 1 Minimal)
【JoinIR Layer】
loop_step 関数:
Jump(k_exit, [i_param], cond=exit_cond)
↓
Pattern 1 lowering:
exit_bindings = [
LoopExitBinding {
carrier_name: "i",
join_exit_value: ValueId(1003), // JoinIR i_param
host_slot: ValueId(3), // Host MIR PHI dst
}
]
【Boundary Layer】
ExitLineReconnector::connect_exit_line():
for binding in exit_bindings:
builder.add_phi_incoming(
block: exit_block_id,
dst: ValueId(3), // host_slot
incoming: (bb6, ValueId(3)) // (exit_pred, remapped join_exit_value)
)
↓
Host MIR:
bb3: ValueId(3) = phi [(bb6, ValueId(3))]
【LLVM Layer】
PhiManager::register_phi(3, 3, phi_value) // PHI を登録
↓
block_lower.py Pass A (非終端命令処理):
vmap_cur = PhiManager.filter_vmap_preserve_phis(builder.vmap, 3)
# → bb3 所有の PHI(3) のみ保持、他ブロックの PHI は除外
↓
Pass A sync:
PhiManager.sync_protect_phis(builder.vmap, vmap_cur)
# → builder.vmap の PHI を上書きしない
↓
Pass B (PHI finalization):
phi_3.add_incoming(val_3, bb6)
↓
Pass C (終端命令処理):
ret phi_3
Design Principles
1. Separation of Concerns
- JoinIR: データ生成のみ(実行なし)
- Boundary: 接続実行のみ(データ保護なし)
- LLVM: PHI保護・管理のみ(生成なし)
2. Box-First Architecture (Phase 132-Post)
- ロジックを Box (クラス/メソッド) にカプセル化
ExitLineReconnectorBox (Boundary)PhiManagerBox (LLVM)
3. SSOT (Single Source of Truth)
exit_bindingsが変数バインディングの唯一の真実builder.vmapの PHI が SSA 値の唯一の真実- metadata 参照の完全排除
4. Fail-Fast
- エラーは早期に明示的に失敗
- フォールバック処理は禁止
- PHI 上書きは panic
Migration from Phase 131
Phase 131 (Before)
- ❌ Jump metadata (
jump_args) から exit PHI を復元 - ❌ Block.metadata 参照の散在
- ❌ PHI 管理ロジックの分散
Phase 132 (After)
- ✅
exit_bindingsで明示的データフロー - ✅ Boundary 層での一元的 PHI 接続
- ✅ metadata 完全削除(Block からも削除)
Phase 132-Post (Box-First Refactoring)
- ✅
PhiManagerBox による PHI 管理ロジック集約 - ✅
filter_vmap_preserve_phis()でフィルタリング簡潔化 - ✅
sync_protect_phis()で保護ロジック再利用可能
Future Work
Pattern 2-5 への拡張
- Pattern 2 (If-in-Loop): 複数変数 exit bindings
- Pattern 3 (Loop-with-If): exit line 分岐処理
- Pattern 4-5: 複雑な exit 条件
PhiManager 拡張候補
- PHI タイプヒント管理
- PHI incoming 検証
- PHI 最適化ヒント
References
- Phase 132 実装ログ:
docs/development/current/main/phases/phase-132/ - Boundary アーキテクチャ:
docs/development/architecture/phase-33-modularization.md - JoinIR 全体設計:
docs/development/current/main/joinir-architecture-overview.md
Last Updated: 2025-12-15 (Phase 132-Post Box-First Refactoring)