Files
hakorune/docs/development/architecture/exit-phi-design.md

216 lines
6.3 KiB
Markdown
Raw Normal View History

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>
2025-12-15 03:17:31 +09:00
# 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`: ループ脱出時の変数バインディング構造
```rust
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 で箱化)
```rust
impl ExitLineReconnector {
fn connect_exit_line(
&self,
boundary: &JoinInlineBoundary,
exit_block_id: BasicBlockId,
exit_predecessor: BasicBlockId,
builder: &mut Builder,
) -> Result<(), String>
}
```
**処理フロー**:
1. `exit_bindings` をイテレート
2. 各 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):
- `PhiManager` Box: PHI ライフサイクル管理
```python
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_phis` dict による PHI ownership tracking
- vmap filtering: ブロック外の PHI を除外
- sync protection: 既存 PHI を上書きしない
**Phase 132-Post 貢献** (Box-First Refactoring):
- `PhiManager` Box 化で 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 (クラス/メソッド) にカプセル化
- `ExitLineReconnector` Box (Boundary)
- `PhiManager` Box (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)
-`PhiManager` Box による 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)