refactor(joinir): Pattern 3 ExitMeta化 - Hardcoded ValueIds削除
Refactoring 5.1: Pattern 3 を Pattern 4 と同じ ExitMeta ベースアーキテクチャに統一化
Changes:
1. loop_with_if_phi_minimal.rs
- 署名: Option<JoinModule> → Result<(JoinModule, JoinFragmentMeta), String>
- ExitMeta 動的生成ロジック追加(sum, count)
- インポート追加: carrier_info::{ExitMeta, JoinFragmentMeta}
2. pattern3_with_if_phi.rs
- Hardcoded 定数削除(PATTERN3_K_EXIT_*_ID 2個削除)
- Manual exit binding 42行 → ExitMetaCollector 4行に置き換え
- インポート追加: ExitMetaCollector
3. loop_patterns/with_if_phi.rs
- Result型変更に対応(.ok()? で変換)
Benefits:
- Pattern 3/4 アーキテクチャ統一化 ✅
- 19行純削減(+55 -74行、3ファイル合計) ✅
- Hardcoded ValueIds 完全撤廃 ✅
- Phase 213 AST-based generalization の基盤強化 ✅
Tests: All tests passing, loop_if_phi.hako outputs "sum=9" correctly
This commit is contained in:
@ -741,22 +741,44 @@
|
|||||||
- **成果**: Pattern routing は完全に成功、AST-based lowerer 汎用化は Phase 213 へ
|
- **成果**: Pattern routing は完全に成功、AST-based lowerer 汎用化は Phase 213 へ
|
||||||
- **ドキュメント**: phase212-5-implementation-complete.md
|
- **ドキュメント**: phase212-5-implementation-complete.md
|
||||||
|
|
||||||
- [ ] **Phase 213: Pattern 3 Lowerer 汎用化(if-sum minimal)** 🚧 **次のフェーズ**
|
- [x] **Phase 213-2: PatternPipelineContext + CarrierUpdateInfo 拡張** ✅ (2025-12-09)
|
||||||
|
- Task 213-2-2: `PatternPipelineContext` に Pattern 3 用フィールド追加
|
||||||
|
- `loop_condition: Option<ASTNode>` - ループ条件 AST 保存
|
||||||
|
- `loop_body: Option<Vec<ASTNode>>` - ループ本体 AST 保存
|
||||||
|
- `loop_update_summary: Option<LoopUpdateSummary>` - キャリア更新情報
|
||||||
|
- Task 213-2-3: `CarrierUpdateInfo` に then/else expression 追加
|
||||||
|
- `then_expr: Option<ASTNode>` - then 分岐更新式
|
||||||
|
- `else_expr: Option<ASTNode>` - else 分岐更新式
|
||||||
|
- **成果**: Phase 213 AST-based generalization の基盤完成
|
||||||
|
|
||||||
|
- 🚧 **Refactoring 5.1: Pattern 3 Hardcoded ValueIds → ExitMeta化** (2025-12-09)
|
||||||
|
- **目的**: Pattern 3 lowerer を Pattern 4 と同じ ExitMeta ベースアーキテクチャに統一化
|
||||||
|
- **変更対象**:
|
||||||
|
1. `loop_with_if_phi_minimal.rs`
|
||||||
|
- 署名: `Option<JoinModule>` → `Result<(JoinModule, JoinFragmentMeta), String>`
|
||||||
|
- ExitMeta 動的生成ロジック追加(k_exit parameters → exit_values HashMap)
|
||||||
|
2. `pattern3_with_if_phi.rs`
|
||||||
|
- Hardcoded 定数削除(`PATTERN3_K_EXIT_SUM_FINAL_ID`, `PATTERN3_K_EXIT_COUNT_FINAL_ID`)
|
||||||
|
- Manual exit binding → `ExitMetaCollector::collect()` に置き換え
|
||||||
|
- **期待効果**: 42 行削減(pattern3_with_if_phi.rs の 22%)
|
||||||
|
- **実装進捗**: Task エージェント実装中
|
||||||
|
- **テスト計画**: `loop_if_phi.hako` / `phase212_if_sum_min.hako` で検証
|
||||||
|
|
||||||
|
- [ ] **Phase 213: Pattern 3 Lowerer 汎用化(if-sum minimal)** 🚧 **次フェーズ**
|
||||||
- **目的**: Pattern 3 lowerer を AST-based に汎用化し、`phase212_if_sum_min.hako` で RC=2 達成
|
- **目的**: Pattern 3 lowerer を AST-based に汎用化し、`phase212_if_sum_min.hako` で RC=2 達成
|
||||||
- **スコープ**:
|
- **前置**: Phase 213-2 + Refactoring 5.1 で基盤・アーキテクチャ統一完了
|
||||||
1. 設計ドキュメント作成
|
- **スコープ(Phase 214 予定)**:
|
||||||
- `phase213-pattern3-if-sum-generalization.md`
|
1. Pattern3IfAnalyzer 実装
|
||||||
- 入力: LoopPatternContext + LoopUpdateSummary + IfPhiContext
|
- Loop body から if statement 抽出
|
||||||
- 出力: JoinModule + ExitMeta(複数キャリア対応)
|
- If condition → BoolExprLowerer で JoinIR lowering
|
||||||
2. P3 lowerer から定数ハードコード削除
|
- Then/else branches → キャリア更新式抽出
|
||||||
- `loop_with_if_phi_minimal.rs` の固定条件/更新(`i<=5`, `i%2==1`, `sum+i`)を削除
|
2. P3 lowerer AST-based 汎用化
|
||||||
- LoopUpdateSummary / BoolExprLowerer / CarrierInfo から動的に AST を読み込み
|
- `loop_condition` から loop limit を動的抽出
|
||||||
|
- `loop_body::If` から if condition を動的抽出
|
||||||
|
- `loop_update_summary` から then/else updates を動的抽出
|
||||||
3. `phase212_if_sum_min.hako` 再実行
|
3. `phase212_if_sum_min.hako` 再実行
|
||||||
- 期待: Pattern 3 routing → JoinIR/MIR/VM → RC=2
|
- 期待: Pattern 3 routing → JoinIR/MIR/VM → RC=2
|
||||||
- **Fail-Fast 戦略**: Verifier panic や制約エラーがあればログを Phase 213 doc に記録
|
- **ドキュメント**: phase213-pattern3-if-sum-generalization.md(設計完了)
|
||||||
- **ドキュメント更新**:
|
|
||||||
- phase212-5-implementation-complete.md に Phase 213 への継続を明記
|
|
||||||
- CURRENT_TASK.md 本項目
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
217
docs/development/current/main/phase213-progress-checkpoint-1.md
Normal file
217
docs/development/current/main/phase213-progress-checkpoint-1.md
Normal file
@ -0,0 +1,217 @@
|
|||||||
|
# Phase 213: Progress Checkpoint 1
|
||||||
|
|
||||||
|
**Date**: 2025-12-09
|
||||||
|
**Status**: ✅ Foundation Complete, Ready for Lowerer Refactoring
|
||||||
|
**Commit**: d7805e59
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🎯 Completed Work
|
||||||
|
|
||||||
|
### ✅ Task 213-2-2: PatternPipelineContext Extension
|
||||||
|
|
||||||
|
**File**: `src/mir/builder/control_flow/joinir/patterns/pattern_pipeline.rs`
|
||||||
|
|
||||||
|
**Changes**:
|
||||||
|
1. Added new fields for Pattern 3:
|
||||||
|
- `loop_condition: Option<ASTNode>` - Loop condition AST
|
||||||
|
- `loop_body: Option<Vec<ASTNode>>` - Loop body AST
|
||||||
|
- `loop_update_summary: Option<LoopUpdateSummary>` - Update expressions
|
||||||
|
|
||||||
|
2. Updated `build_pattern_context()` for Pattern3:
|
||||||
|
- Stores `condition.clone()` in `loop_condition`
|
||||||
|
- Stores `body.to_vec()` in `loop_body`
|
||||||
|
- Placeholder `None` for `loop_update_summary` (TODO: Task 213-2-4)
|
||||||
|
|
||||||
|
3. Updated test cases with new fields
|
||||||
|
|
||||||
|
### ✅ Task 213-2-3: CarrierUpdateInfo Extension
|
||||||
|
|
||||||
|
**File**: `src/mir/join_ir/lowering/loop_update_summary.rs`
|
||||||
|
|
||||||
|
**Changes**:
|
||||||
|
1. Extended `CarrierUpdateInfo` struct:
|
||||||
|
- `then_expr: Option<ASTNode>` - Then branch update expression
|
||||||
|
- `else_expr: Option<ASTNode>` - Else branch update expression
|
||||||
|
|
||||||
|
2. Updated `analyze_loop_updates()`:
|
||||||
|
- Default `None` for `then_expr`/`else_expr`
|
||||||
|
- Comment: "Will be populated by Pattern 3 analyzer"
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📊 Current State Analysis
|
||||||
|
|
||||||
|
### MIR Analysis for `phase212_if_sum_min.hako`
|
||||||
|
|
||||||
|
**Expected vs Actual**:
|
||||||
|
|
||||||
|
| Element | Expected | Actual (Hardcoded) |
|
||||||
|
|---------|----------|-------------------|
|
||||||
|
| Loop limit | `i < 3` | `i <= 5` |
|
||||||
|
| Loop cond | `icmp Lt %8, %18` | `icmp Le %8, %18` |
|
||||||
|
| If cond | `i > 0` | `i % 2 == 1` |
|
||||||
|
| If cond code | `icmp Gt %8, %zero` | `%8 Mod %2; icmp Eq ... %1` |
|
||||||
|
| Then update | `sum + 1` | `sum + i` |
|
||||||
|
| Then code | `%9 Add %const_1` | `%9 Add %8` |
|
||||||
|
|
||||||
|
**Root Cause**: `loop_with_if_phi_minimal.rs` lines 217-385 are completely hardcoded for `loop_if_phi.hako` test pattern.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔄 Next Steps (3 Approaches)
|
||||||
|
|
||||||
|
### Approach A: Full AST-Based Generalization (Phase 213 Original Plan)
|
||||||
|
|
||||||
|
**Tasks**:
|
||||||
|
1. Create `Pattern3IfAnalyzer` module
|
||||||
|
2. Extract if statement from loop body
|
||||||
|
3. Parse then/else branches for carrier updates
|
||||||
|
4. Populate `LoopUpdateSummary` with AST expressions
|
||||||
|
5. Replace hardcoded conditions in lowerer
|
||||||
|
6. Replace hardcoded updates in lowerer
|
||||||
|
7. Return `ExitMeta` instead of hardcoded ValueIds
|
||||||
|
|
||||||
|
**Pros**: Complete generalization, supports all if-sum patterns
|
||||||
|
**Cons**: Large scope, ~500-800 lines of new code
|
||||||
|
|
||||||
|
### Approach B: Minimal Incremental (80/20 Rule)
|
||||||
|
|
||||||
|
**Tasks**:
|
||||||
|
1. Just replace the 3 hardcoded constants:
|
||||||
|
- Loop limit: 5 → extract from AST condition
|
||||||
|
- If condition: `i % 2 == 1` → extract from AST if statement
|
||||||
|
- Update value: `i` → extract from AST assignment
|
||||||
|
2. Keep existing structure, minimal changes
|
||||||
|
|
||||||
|
**Pros**: Small scope, fast to implement, gets `phase212_if_sum_min.hako` working
|
||||||
|
**Cons**: Still not fully generic, will need refactoring later
|
||||||
|
|
||||||
|
### Approach C: Hybrid - BoolExprLowerer First
|
||||||
|
|
||||||
|
**Tasks**:
|
||||||
|
1. Focus on condition lowering only (loop + if)
|
||||||
|
2. Keep update expressions hardcoded for now
|
||||||
|
3. Use existing `condition_to_joinir` infrastructure
|
||||||
|
4. Defer update generalization to Phase 214
|
||||||
|
|
||||||
|
**Pros**: Leverages existing infrastructure, cleaner architecture
|
||||||
|
**Cons**: `phase212_if_sum_min.hako` still won't work fully
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 💭 Analysis & Recommendation
|
||||||
|
|
||||||
|
### Key Insight from Phase 212.5
|
||||||
|
|
||||||
|
Phase 212.5 discovered that:
|
||||||
|
1. Pattern routing works correctly (✅ Pattern 3 detected)
|
||||||
|
2. MIR PHI generation works (✅ `%31 = phi` created)
|
||||||
|
3. **Only the lowerer's hardcoded values are wrong**
|
||||||
|
|
||||||
|
This means the JoinIR → MIR pipeline is solid. We just need to feed it the right JoinIR.
|
||||||
|
|
||||||
|
### Recommendation: Approach B (Minimal Incremental)
|
||||||
|
|
||||||
|
**Rationale**:
|
||||||
|
1. **User's 80/20 philosophy**: "完璧より進捗" (progress over perfection)
|
||||||
|
2. **Fail-Fast principle**: Get `phase212_if_sum_min.hako` working first
|
||||||
|
3. **Box Theory**: Make minimal, reversible change
|
||||||
|
4. **Evidence-based**: Phase 212.5 proved the pipeline works
|
||||||
|
|
||||||
|
**Implementation Plan**:
|
||||||
|
1. Extract loop condition from `ctx.loop_condition` AST
|
||||||
|
2. Extract if condition from `ctx.loop_body` if statement
|
||||||
|
3. Extract update expression from if-then assignment
|
||||||
|
4. Replace 3 hardcoded sections in `loop_with_if_phi_minimal.rs`
|
||||||
|
5. Test with `phase212_if_sum_min.hako` → RC=2 ✅
|
||||||
|
6. Keep existing tests working (backward compatibility)
|
||||||
|
|
||||||
|
**Estimated effort**: 2-3 hours (vs 8-10 hours for Approach A)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔍 Technical Details for Approach B
|
||||||
|
|
||||||
|
### What Needs to Change
|
||||||
|
|
||||||
|
**File**: `src/mir/join_ir/lowering/loop_with_if_phi_minimal.rs`
|
||||||
|
|
||||||
|
**Section 1: Loop Condition (lines 217-233)**
|
||||||
|
```rust
|
||||||
|
// Before (hardcoded):
|
||||||
|
loop_step_func.body.push(JoinInst::Compute(MirLikeInst::Const {
|
||||||
|
dst: const_5,
|
||||||
|
value: ConstValue::Integer(5), // ← Hardcoded!
|
||||||
|
}));
|
||||||
|
loop_step_func.body.push(JoinInst::Compute(MirLikeInst::Compare {
|
||||||
|
dst: cmp_le,
|
||||||
|
op: CompareOp::Le, // ← Hardcoded!
|
||||||
|
lhs: i_param,
|
||||||
|
rhs: const_5,
|
||||||
|
}));
|
||||||
|
|
||||||
|
// After (AST-based):
|
||||||
|
// Extract from ctx.loop_condition: "i < 3"
|
||||||
|
// Lower to JoinIR using existing infrastructure
|
||||||
|
```
|
||||||
|
|
||||||
|
**Section 2: If Condition (lines 254-288)**
|
||||||
|
```rust
|
||||||
|
// Before (hardcoded):
|
||||||
|
// const 2, mod, const 1, eq → (i % 2 == 1)
|
||||||
|
|
||||||
|
// After (AST-based):
|
||||||
|
// Extract from loop_body if statement: "i > 0"
|
||||||
|
// Lower to JoinIR: const 0, cmp Gt
|
||||||
|
```
|
||||||
|
|
||||||
|
**Section 3: Update Expression (lines 290-298)**
|
||||||
|
```rust
|
||||||
|
// Before (hardcoded):
|
||||||
|
loop_step_func.body.push(JoinInst::Compute(MirLikeInst::BinOp {
|
||||||
|
dst: sum_then,
|
||||||
|
op: BinOpKind::Add,
|
||||||
|
lhs: sum_param,
|
||||||
|
rhs: i_param, // ← Hardcoded! Should be const 1
|
||||||
|
}));
|
||||||
|
|
||||||
|
// After (AST-based):
|
||||||
|
// Extract from then-branch assignment: "sum = sum + 1"
|
||||||
|
// Lower to JoinIR: sum_param Add const_1
|
||||||
|
```
|
||||||
|
|
||||||
|
### Helper Functions Needed
|
||||||
|
|
||||||
|
```rust
|
||||||
|
// Extract loop condition details
|
||||||
|
fn extract_loop_condition(condition: &ASTNode)
|
||||||
|
-> Result<(CompareOp, i64), String>
|
||||||
|
|
||||||
|
// Extract if statement from loop body
|
||||||
|
fn extract_if_statement(body: &[ASTNode])
|
||||||
|
-> Result<&ASTNode, String>
|
||||||
|
|
||||||
|
// Extract if condition details
|
||||||
|
fn extract_if_condition(if_node: &ASTNode)
|
||||||
|
-> Result<(CompareOp, i64), String>
|
||||||
|
|
||||||
|
// Extract update value from assignment
|
||||||
|
fn extract_update_value(assignment: &ASTNode)
|
||||||
|
-> Result<i64, String>
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📋 Decision Point
|
||||||
|
|
||||||
|
**Question for user**: Which approach should we take?
|
||||||
|
|
||||||
|
A. Full AST-based generalization (Approach A)
|
||||||
|
B. Minimal incremental replacement (Approach B) ← **Recommended**
|
||||||
|
C. Hybrid BoolExprLowerer-first (Approach C)
|
||||||
|
D. Different approach?
|
||||||
|
|
||||||
|
**Current blockers**: None - foundation is complete
|
||||||
|
**Current branch**: main (`d7805e59`)
|
||||||
|
**Build status**: ✅ Passing
|
||||||
199
docs/development/current/main/phase213-session-summary.md
Normal file
199
docs/development/current/main/phase213-session-summary.md
Normal file
@ -0,0 +1,199 @@
|
|||||||
|
# Phase 213: セッション進捗サマリー
|
||||||
|
|
||||||
|
**Date**: 2025-12-09 (Continuation Session)
|
||||||
|
**Status**: 🚧 進行中
|
||||||
|
**Current Commit**: d7805e59 (Phase 213-2 & Refactoring計画)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📊 セッション成果
|
||||||
|
|
||||||
|
### ✅ Phase 213-2: データ構造拡張完了
|
||||||
|
|
||||||
|
**完了内容:**
|
||||||
|
1. `PatternPipelineContext` 拡張
|
||||||
|
- `loop_condition: Option<ASTNode>` - ループ条件AST保存
|
||||||
|
- `loop_body: Option<Vec<ASTNode>>` - ループ本体AST保存
|
||||||
|
- `loop_update_summary: Option<LoopUpdateSummary>` - キャリア更新情報
|
||||||
|
|
||||||
|
2. `CarrierUpdateInfo` 拡張
|
||||||
|
- `then_expr: Option<ASTNode>` - then分岐の更新式
|
||||||
|
- `else_expr: Option<ASTNode>` - else分岐の更新式
|
||||||
|
|
||||||
|
3. `build_pattern_context()` 更新
|
||||||
|
- Pattern 3 向けにループ条件・本体を保存
|
||||||
|
|
||||||
|
**コード削減**: 0行(新規追加)
|
||||||
|
**テスト**: ✅ Build成功、既存テスト合格
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 🔍 リファクタリング機会調査完了
|
||||||
|
|
||||||
|
**調査範囲:** JoinIR Lowering層 + Pattern Builder層
|
||||||
|
|
||||||
|
**発見:**
|
||||||
|
- **共通化度**: 45% (1,500行の重複コード)
|
||||||
|
- **レガシー度**: 25% (hardcode + PoC コメント)
|
||||||
|
- **削減可能**: 500-700行 (14-20%)
|
||||||
|
|
||||||
|
**リファクタリング提案(優先度順):**
|
||||||
|
|
||||||
|
| # | 項目 | 優先度 | 所要時間 | 削減行数 |
|
||||||
|
|---|------|--------|---------|---------|
|
||||||
|
| 5.1 | Pattern 3 Hardcode削除 + ExitMeta化 | HIGH | 3-4h | 22行 |
|
||||||
|
| 5.2 | Dummy Count Backward Compat削除 | HIGH | 2-3h | 20行 |
|
||||||
|
| 5.3 | Loop Template Extraction | MEDIUM | 4-6h | 150行 |
|
||||||
|
| 5.4 | ValueId Allocation標準化 | MEDIUM | 3-4h | 200行 |
|
||||||
|
| 5.5 | LowererTrait化 | LOW | 8-10h | 大幅改修 |
|
||||||
|
| 5.6 | PatternPipeline Cleanup | LOW | 2-3h | 細かい整理 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 🚀 実装中: Refactoring 5.1
|
||||||
|
|
||||||
|
**目標:** Pattern 3 を Pattern 4 と同じ ExitMeta ベースアーキテクチャに統一化
|
||||||
|
|
||||||
|
**変更対象:**
|
||||||
|
1. `loop_with_if_phi_minimal.rs`
|
||||||
|
- 署名: `Option<JoinModule>` → `Result<(JoinModule, JoinFragmentMeta), String>`
|
||||||
|
- ExitMeta 動的生成ロジック追加
|
||||||
|
|
||||||
|
2. `pattern3_with_if_phi.rs`
|
||||||
|
- Hardcoded 定数削除(`PATTERN3_K_EXIT_*_ID`)
|
||||||
|
- Manual exit binding → ExitMetaCollector に置き換え
|
||||||
|
|
||||||
|
**期待効果:**
|
||||||
|
- ✅ Hardcoded ValueIds 完全削除
|
||||||
|
- ✅ Pattern 3/4 アーキテクチャ統一化
|
||||||
|
- ✅ 42行削減(pattern3_with_if_phi.rs の22%)
|
||||||
|
- ✅ Phase 213 AST-based generalization の基盤強化
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🏗️ アーキテクチャの進化
|
||||||
|
|
||||||
|
### Before (Phase 195)
|
||||||
|
|
||||||
|
```
|
||||||
|
Pattern 3 Lowerer (Test-Only PoC)
|
||||||
|
├─ Hardcoded loop condition: i <= 5
|
||||||
|
├─ Hardcoded if condition: i % 2 == 1
|
||||||
|
├─ Hardcoded updates: sum+i, count+1
|
||||||
|
└─ Hardcoded exit ValueIds: ValueId(24), ValueId(25)
|
||||||
|
↓
|
||||||
|
Pattern 3 Builder
|
||||||
|
├─ Manual exit binding construction
|
||||||
|
├─ Dummy count backward compat hack
|
||||||
|
└─ if has_count { ... } else { ... } 複雑な分岐
|
||||||
|
```
|
||||||
|
|
||||||
|
### After Refactoring 5.1 (Phase 213)
|
||||||
|
|
||||||
|
```
|
||||||
|
Pattern 3 Lowerer (ExitMeta化)
|
||||||
|
├─ JoinModule + JoinFragmentMeta を返す
|
||||||
|
├─ ExitMeta 動的生成: {"sum": ValueId(...), "count": ValueId(...)}
|
||||||
|
└─ Result型エラーハンドリング
|
||||||
|
↓
|
||||||
|
Pattern 3 Builder
|
||||||
|
├─ ExitMetaCollector で動的 exit binding 生成
|
||||||
|
├─ Hardcoded 定数削除
|
||||||
|
└─ Carrier validation(Pattern 4と同じ)
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📝 次のステップ(推奨順)
|
||||||
|
|
||||||
|
### Step 1: Refactoring 5.1 完了待機 (進行中)
|
||||||
|
- Task エージェント実装中
|
||||||
|
- Build & Test 確認待ち
|
||||||
|
|
||||||
|
### Step 2: Refactoring 5.1 統合 & コミット
|
||||||
|
- 実装結果確認
|
||||||
|
- 既存テスト合格確認
|
||||||
|
- コミット & ドキュメント更新
|
||||||
|
|
||||||
|
### Step 3: Refactoring 5.2 実装(選択的)
|
||||||
|
- Dummy count backward compat 削除
|
||||||
|
- Single-carrier テスト廃止 or 更新
|
||||||
|
- Multi-carrier の完全化
|
||||||
|
|
||||||
|
### Step 4: Phase 213 本体進行(Phase 214に延期予定)
|
||||||
|
- Pattern3IfAnalyzer 実装
|
||||||
|
- AST-based condition lowering
|
||||||
|
- AST-based update expression lowering
|
||||||
|
- ExitMeta による exit binding 統一化
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🎯 Phase 213 最終目標 (Phase 213 + 214)
|
||||||
|
|
||||||
|
**短期(Phase 213):**
|
||||||
|
- ✅ PatternPipelineContext 拡張(DONE)
|
||||||
|
- ✅ CarrierUpdateInfo 拡張(DONE)
|
||||||
|
- 🚧 Refactoring 5.1-5.2(実装中)
|
||||||
|
|
||||||
|
**中期(Phase 214):**
|
||||||
|
- Pattern3IfAnalyzer 実装
|
||||||
|
- AST-based generalization
|
||||||
|
- `phase212_if_sum_min.hako` → RC=2 達成
|
||||||
|
|
||||||
|
**長期(Phase 220+):**
|
||||||
|
- Refactoring 5.3-5.5(アーキテクチャ完成化)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📚 作成ドキュメント
|
||||||
|
|
||||||
|
1. **phase213-progress-checkpoint-1.md**
|
||||||
|
- 基盤完成時点での進捗報告
|
||||||
|
- 3つのアプローチ提案
|
||||||
|
|
||||||
|
2. **refactoring-5-1-pattern3-exitmeta.md**
|
||||||
|
- 詳細な実装計画(5ステップ)
|
||||||
|
- Before/After コード比較
|
||||||
|
- テスト戦略 & リスク管理
|
||||||
|
|
||||||
|
3. **phase213-session-summary.md** (このファイル)
|
||||||
|
- セッション全体の進捗まとめ
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔗 関連リソース
|
||||||
|
|
||||||
|
- **Master Plan**: docs/private/roadmap2/phases/00_MASTER_ROADMAP.md
|
||||||
|
- **Phase 213 Design Doc**: phase213-pattern3-if-sum-generalization.md
|
||||||
|
- **Phase 212.5 Report**: phase212-5-implementation-complete.md
|
||||||
|
- **Refactoring 5.1 Plan**: refactoring-5-1-pattern3-exitmeta.md
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ✨ Session Highlights
|
||||||
|
|
||||||
|
### 🎓 学習ポイント
|
||||||
|
|
||||||
|
1. **Box Theory の実践**
|
||||||
|
- Pattern 3 を修正可能・差し替え可能な箱として設計
|
||||||
|
- ExitMeta による境界の明確化
|
||||||
|
|
||||||
|
2. **アーキテクチャ統一化**
|
||||||
|
- Pattern 3/4 が同じアーキテクチャになることで保守性向上
|
||||||
|
- レガシーコード(hardcode)を完全排除
|
||||||
|
|
||||||
|
3. **段階的改善(80/20ルール)**
|
||||||
|
- Phase 213-2: データ構造基盤(DONE)
|
||||||
|
- Phase 213: Refactoring 整理整頓(実装中)
|
||||||
|
- Phase 214: AST-based generalization(計画)
|
||||||
|
|
||||||
|
### 🚀 次のセッションへの引き継ぎ
|
||||||
|
|
||||||
|
- **Refactoring 5.1 の実装完了**
|
||||||
|
- **Phase 213 本体(AST-based lowering)への準備完了**
|
||||||
|
- **包括的な計画ドキュメント整備完了**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Status**: Phase 213 の基盤構築完了 ✅
|
||||||
|
**Next**: Refactoring 5.1 の結果確認 & 統合
|
||||||
@ -0,0 +1,360 @@
|
|||||||
|
# Refactoring 5.1: Pattern 3 Hardcoded ValueIds → ExitMeta化
|
||||||
|
|
||||||
|
**Date**: 2025-12-09
|
||||||
|
**Status**: 🚧 In Progress
|
||||||
|
**Estimated Time**: 3-4 hours
|
||||||
|
**Priority**: HIGH
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📋 目標
|
||||||
|
|
||||||
|
Pattern 3 lowerer(`loop_with_if_phi_minimal.rs`)を Pattern 4 と同じ ExitMeta ベースのアーキテクチャに統一化する。これにより:
|
||||||
|
|
||||||
|
1. ✅ Hardcoded ValueIds 定数削除(`PATTERN3_K_EXIT_*_ID`)
|
||||||
|
2. ✅ Exit binding の動的生成
|
||||||
|
3. ✅ Multi-carrier support の完全化
|
||||||
|
4. ✅ Pattern 3/4 の共通化度向上
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔄 変更対象ファイル
|
||||||
|
|
||||||
|
### ファイル1: `src/mir/join_ir/lowering/loop_with_if_phi_minimal.rs`
|
||||||
|
|
||||||
|
**現在:**
|
||||||
|
```rust
|
||||||
|
pub(crate) fn lower_loop_with_if_phi_pattern(
|
||||||
|
_scope: LoopScopeShape,
|
||||||
|
join_value_space: &mut JoinValueSpace,
|
||||||
|
) -> Option<JoinModule>
|
||||||
|
```
|
||||||
|
|
||||||
|
**変更後:**
|
||||||
|
```rust
|
||||||
|
use crate::mir::join_ir::lowering::join_fragment_meta::JoinFragmentMeta;
|
||||||
|
|
||||||
|
pub(crate) fn lower_loop_with_if_phi_pattern(
|
||||||
|
_scope: LoopScopeShape,
|
||||||
|
join_value_space: &mut JoinValueSpace,
|
||||||
|
) -> Result<(JoinModule, JoinFragmentMeta), String>
|
||||||
|
```
|
||||||
|
|
||||||
|
**変更内容:**
|
||||||
|
1. 戻り値を `Option<JoinModule>` → `Result<(JoinModule, JoinFragmentMeta), String>` に変更
|
||||||
|
2. `JoinFragmentMeta` を構築して返す
|
||||||
|
3. ExitMeta を動的に生成
|
||||||
|
|
||||||
|
### ファイル2: `src/mir/builder/control_flow/joinir/patterns/pattern3_with_if_phi.rs`
|
||||||
|
|
||||||
|
**現在:**
|
||||||
|
```rust
|
||||||
|
const PATTERN3_K_EXIT_SUM_FINAL_ID: ValueId = ValueId(24); // Hardcoded!
|
||||||
|
const PATTERN3_K_EXIT_COUNT_FINAL_ID: ValueId = ValueId(25); // Hardcoded!
|
||||||
|
|
||||||
|
// Lines 118-164: has_count 条件分岐で exit_bindings を手動構築
|
||||||
|
let exit_bindings = if has_count {
|
||||||
|
vec![
|
||||||
|
LoopExitBinding {
|
||||||
|
join_exit_value: PATTERN3_K_EXIT_SUM_FINAL_ID, // ← Hardcoded!
|
||||||
|
...
|
||||||
|
},
|
||||||
|
...
|
||||||
|
]
|
||||||
|
} else {
|
||||||
|
// Dummy count hack
|
||||||
|
...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**変更後:**
|
||||||
|
```rust
|
||||||
|
// Hardcoded 定数削除(削除)
|
||||||
|
|
||||||
|
// Lines 300-314: ExitMeta から exit_bindings を動的生成
|
||||||
|
let exit_bindings = ExitMetaCollector::collect(
|
||||||
|
self,
|
||||||
|
&exit_meta,
|
||||||
|
debug,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Carrier validation(Pattern 4と同じ)
|
||||||
|
for carrier in &carrier_info.carriers {
|
||||||
|
if !exit_bindings.iter().any(|b| b.carrier_name == carrier.name) {
|
||||||
|
return Err(format!(
|
||||||
|
"[cf_loop/pattern3] Carrier '{}' not found in exit bindings",
|
||||||
|
carrier.name
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔧 実装ステップ
|
||||||
|
|
||||||
|
### Step 1: `loop_with_if_phi_minimal.rs` の k_exit 関数を分析
|
||||||
|
|
||||||
|
**現在の k_exit 実装(lines 401-415):**
|
||||||
|
```rust
|
||||||
|
let mut k_exit_func = JoinFunction::new(
|
||||||
|
k_exit_id,
|
||||||
|
"k_exit".to_string(),
|
||||||
|
vec![sum_final, count_final], // Phase 195: Multi-carrier
|
||||||
|
);
|
||||||
|
|
||||||
|
k_exit_func.body.push(JoinInst::Ret {
|
||||||
|
value: Some(sum_final),
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
**分析:**
|
||||||
|
- `k_exit` の parameters: `[sum_final, count_final]` が exit PHI
|
||||||
|
- k_exit は `sum_final` を return(最初の carrier)
|
||||||
|
- ExitMeta として記録すべき情報:
|
||||||
|
- `sum` → `sum_final` (ValueId(24))
|
||||||
|
- `count` → `count_final` (ValueId(25))
|
||||||
|
|
||||||
|
### Step 2: ExitMeta 構築ロジック追加
|
||||||
|
|
||||||
|
lowerer の最後に以下を追加:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
// Phase 213: Build ExitMeta for dynamic exit binding generation
|
||||||
|
use crate::mir::join_ir::lowering::join_fragment_meta::JoinFragmentMeta;
|
||||||
|
use crate::mir::join_ir::lowering::exit_meta::ExitMeta;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
let mut exit_values = HashMap::new();
|
||||||
|
|
||||||
|
// Map carrier names to their k_exit parameter ValueIds
|
||||||
|
exit_values.insert("sum".to_string(), sum_final);
|
||||||
|
if has_count {
|
||||||
|
exit_values.insert("count".to_string(), count_final);
|
||||||
|
}
|
||||||
|
|
||||||
|
let exit_meta = ExitMeta {
|
||||||
|
exit_values,
|
||||||
|
exit_func_id: k_exit_id,
|
||||||
|
};
|
||||||
|
|
||||||
|
let fragment_meta = JoinFragmentMeta {
|
||||||
|
exit_meta,
|
||||||
|
// その他フィールド
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok((join_module, fragment_meta))
|
||||||
|
```
|
||||||
|
|
||||||
|
**注:** `has_count` フラグは必要。multi-carrier に対応するため。
|
||||||
|
|
||||||
|
### Step 3: `pattern3_with_if_phi.rs` での lowerer 呼び出し変更
|
||||||
|
|
||||||
|
**現在(lines 109-116):**
|
||||||
|
```rust
|
||||||
|
let join_module = match lower_loop_with_if_phi_pattern(ctx.loop_scope, &mut join_value_space) {
|
||||||
|
Some(module) => module,
|
||||||
|
None => {
|
||||||
|
trace::trace().debug("pattern3", "Pattern 3 lowerer returned None");
|
||||||
|
return Ok(None);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
**変更後:**
|
||||||
|
```rust
|
||||||
|
let (join_module, exit_meta) = match lower_loop_with_if_phi_pattern(ctx.loop_scope, &mut join_value_space) {
|
||||||
|
Ok(result) => result,
|
||||||
|
Err(e) => {
|
||||||
|
trace::trace().debug("pattern3", &format!("Pattern 3 lowerer failed: {}", e));
|
||||||
|
return Err(format!("[cf_loop/pattern3] Lowering failed: {}", e));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
trace::trace().debug(
|
||||||
|
"pattern3",
|
||||||
|
&format!("ExitMeta: {} exit values", exit_meta.exit_values.len())
|
||||||
|
);
|
||||||
|
for (carrier_name, join_value) in &exit_meta.exit_values {
|
||||||
|
trace::trace().debug(
|
||||||
|
"pattern3",
|
||||||
|
&format!(" {} → ValueId({})", carrier_name, join_value.0)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 4: Exit binding 動的生成(Hardcoded 定数削除)
|
||||||
|
|
||||||
|
**現在(lines 8-30, 118-164):**
|
||||||
|
```rust
|
||||||
|
// Hardcoded constants
|
||||||
|
const PATTERN3_K_EXIT_SUM_FINAL_ID: ValueId = ValueId(24);
|
||||||
|
const PATTERN3_K_EXIT_COUNT_FINAL_ID: ValueId = ValueId(25);
|
||||||
|
|
||||||
|
// Manual exit_bindings construction with has_count branching
|
||||||
|
let exit_bindings = if has_count {
|
||||||
|
vec![
|
||||||
|
LoopExitBinding {
|
||||||
|
carrier_name: "sum".to_string(),
|
||||||
|
join_exit_value: PATTERN3_K_EXIT_SUM_FINAL_ID, // ← Hardcoded!
|
||||||
|
host_slot: sum_var_id,
|
||||||
|
},
|
||||||
|
LoopExitBinding {
|
||||||
|
carrier_name: "count".to_string(),
|
||||||
|
join_exit_value: PATTERN3_K_EXIT_COUNT_FINAL_ID, // ← Hardcoded!
|
||||||
|
host_slot: count_var_id,
|
||||||
|
}
|
||||||
|
]
|
||||||
|
} else {
|
||||||
|
// Single-carrier hack
|
||||||
|
...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**削除/変更:**
|
||||||
|
```rust
|
||||||
|
// Hardcoded constants(削除)
|
||||||
|
// const PATTERN3_K_EXIT_SUM_FINAL_ID: ValueId = ValueId(24);
|
||||||
|
// const PATTERN3_K_EXIT_COUNT_FINAL_ID: ValueId = ValueId(25);
|
||||||
|
|
||||||
|
// Dynamic exit binding generation(追加)
|
||||||
|
use super::super::merge::exit_line::meta_collector::ExitMetaCollector;
|
||||||
|
let exit_bindings = ExitMetaCollector::collect(
|
||||||
|
self,
|
||||||
|
&exit_meta,
|
||||||
|
debug,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Carrier validation
|
||||||
|
for carrier in &carrier_info.carriers {
|
||||||
|
if !exit_bindings.iter().any(|b| b.carrier_name == carrier.name) {
|
||||||
|
return Err(format!(
|
||||||
|
"[cf_loop/pattern3] Carrier '{}' not found in exit bindings",
|
||||||
|
carrier.name
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 5: Dummy Count Backward Compat 簡略化
|
||||||
|
|
||||||
|
**現在(lines 145-164):**
|
||||||
|
```rust
|
||||||
|
if has_count {
|
||||||
|
// Multi-carrier case
|
||||||
|
(vec![...], vec![...], vec![...])
|
||||||
|
} else {
|
||||||
|
// Single-carrier case with Dummy void
|
||||||
|
let dummy_count_id = constant::emit_void(self);
|
||||||
|
(vec![...], vec![..., dummy_count_id], vec![...])
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**簡略化:**
|
||||||
|
```rust
|
||||||
|
// Phase 213: Always use multi-carrier structure
|
||||||
|
// Single-carrier tests will use dummy void internally
|
||||||
|
let join_inputs = vec![ValueId(0), ValueId(1), ValueId(2)];
|
||||||
|
let mut host_inputs = vec![ctx.loop_var_id, sum_var_id];
|
||||||
|
|
||||||
|
if has_count {
|
||||||
|
host_inputs.push(carrier_count_var_id);
|
||||||
|
} else {
|
||||||
|
// Use void dummy for backward compat
|
||||||
|
host_inputs.push(constant::emit_void(self));
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📊 Before/After Code Change Summary
|
||||||
|
|
||||||
|
### `loop_with_if_phi_minimal.rs`
|
||||||
|
|
||||||
|
| 項目 | Before | After | 削減 |
|
||||||
|
|------|--------|-------|------|
|
||||||
|
| 関数署名 | `Option<JoinModule>` | `Result<(JoinModule, JoinFragmentMeta)>` | - |
|
||||||
|
| k_exit 構築 | あり | あり(変更なし) | 0行 |
|
||||||
|
| ExitMeta 構築 | なし | 新規追加 | +20行 |
|
||||||
|
| **計** | 428行 | 448行 | +20行 |
|
||||||
|
|
||||||
|
### `pattern3_with_if_phi.rs`
|
||||||
|
|
||||||
|
| 項目 | Before | After | 削減 |
|
||||||
|
|------|--------|-------|------|
|
||||||
|
| Hardcoded 定数 | 2個(lines 8-30) | 削除 | -2行 |
|
||||||
|
| Manual exit binding | あり(lines 118-164) | ExitMetaCollector化 | -40行 |
|
||||||
|
| Dummy count hack | あり | 簡略化 | -5行 |
|
||||||
|
| Lowerer呼び出し | None/Some | Ok/Err | -5行 |
|
||||||
|
| ExitMeta debug | なし | 新規追加 | +10行 |
|
||||||
|
| **計** | 191行 | 149行 | **-42行(22%削減)** |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ✅ テスト戦略
|
||||||
|
|
||||||
|
### Test 1: `loop_if_phi.hako` (既存 test)
|
||||||
|
|
||||||
|
**動作確認:**
|
||||||
|
```bash
|
||||||
|
./target/release/hakorune --dump-mir apps/tests/loop_if_phi.hako 2>&1 | grep -A 5 "k_exit"
|
||||||
|
```
|
||||||
|
|
||||||
|
**期待:** k_exit が sum/count を正しく処理(変わらず)
|
||||||
|
|
||||||
|
### Test 2: Multi-carrier tests(Phase 195)
|
||||||
|
|
||||||
|
**確認対象:**
|
||||||
|
- `test_pattern3_multi_carrier_sum_count`
|
||||||
|
- Carrier binding が動的に生成されることを確認
|
||||||
|
|
||||||
|
### Test 3: Cargo test
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cargo test --release pattern3 2>&1 | tail -20
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🚨 リスク & ミティゲーション
|
||||||
|
|
||||||
|
### リスク 1: ExitMeta 構築が複雑
|
||||||
|
|
||||||
|
**ミティゲーション:**
|
||||||
|
- Pattern 4 のコードをコピーペースト基準にする
|
||||||
|
- 最小限の変更に留める
|
||||||
|
|
||||||
|
### リスク 2: ExitMetaCollector の動作確認
|
||||||
|
|
||||||
|
**ミティゲーション:**
|
||||||
|
- Pattern 4 で既に使用済み(実績あり)
|
||||||
|
- Carrier validation で エラー検出
|
||||||
|
|
||||||
|
### リスク 3: Dummy count backward compat 破損
|
||||||
|
|
||||||
|
**ミティゲーション:**
|
||||||
|
- has_count フラグで分岐を保つ
|
||||||
|
- 古い単一キャリア テストは動作のまま
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📝 Checklist
|
||||||
|
|
||||||
|
- [ ] Step 1: k_exit 実装分析完了
|
||||||
|
- [ ] Step 2: ExitMeta 構築ロジック追加
|
||||||
|
- [ ] Step 3: lowerer 呼び出し変更
|
||||||
|
- [ ] Step 4: Hardcoded 定数削除 + ExitMetaCollector 導入
|
||||||
|
- [ ] Step 5: Dummy count 簡略化
|
||||||
|
- [ ] Step 6: Build 成功確認
|
||||||
|
- [ ] Step 7: Test 実行確認
|
||||||
|
- [ ] Step 8: Commit & Document 更新
|
||||||
|
- [ ] Refactoring 5.1 COMPLETE ✅
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📚 参考資料
|
||||||
|
|
||||||
|
- Pattern 4 実装: `src/mir/builder/control_flow/joinir/patterns/pattern4_with_continue.rs` (lines 300-380)
|
||||||
|
- ExitMetaCollector: `src/mir/builder/control_flow/joinir/merge/exit_line/meta_collector.rs`
|
||||||
|
- JoinFragmentMeta: `src/mir/join_ir/lowering/join_fragment_meta.rs`
|
||||||
|
|
||||||
@ -3,31 +3,11 @@
|
|||||||
use crate::ast::ASTNode;
|
use crate::ast::ASTNode;
|
||||||
use crate::mir::builder::MirBuilder;
|
use crate::mir::builder::MirBuilder;
|
||||||
use crate::mir::ValueId;
|
use crate::mir::ValueId;
|
||||||
|
use super::super::merge::exit_line::meta_collector::ExitMetaCollector;
|
||||||
use super::super::trace;
|
use super::super::trace;
|
||||||
|
|
||||||
/// Phase 179-A / Phase 195: Expected ValueIds for k_exit parameters in Pattern 3
|
// Phase 213: Hardcoded ValueIds removed - now using ExitMeta-based exit binding generation
|
||||||
/// These correspond to the exit PHI inputs in the JoinIR lowering for loop_with_if_phi_minimal
|
// See: ExitMetaCollector usage below (lines 115-135)
|
||||||
///
|
|
||||||
/// # TODO (Phase 179 Task 2): Convert to ExitMeta-based exit binding generation
|
|
||||||
///
|
|
||||||
/// **Current State**: Hardcoded ValueIds - fragile and non-reusable
|
|
||||||
///
|
|
||||||
/// **Why it's hardcoded**:
|
|
||||||
/// - Pattern 3's lowerer (`lower_loop_with_if_phi_pattern`) returns `Option<JoinModule>`
|
|
||||||
/// - Unlike Pattern 4 which returns `(JoinModule, JoinFragmentMeta)`
|
|
||||||
/// - No ExitMeta available to dynamically look up exit PHI ValueIds
|
|
||||||
///
|
|
||||||
/// **Migration Path** (when Pattern 3 lowerer is updated):
|
|
||||||
/// 1. Change `lower_loop_with_if_phi_pattern` to return `(JoinModule, JoinFragmentMeta)`
|
|
||||||
/// 2. Remove these constants
|
|
||||||
/// 3. Use ExitMeta loop (like Pattern 4 lines 350-378) to generate exit_bindings dynamically
|
|
||||||
/// 4. See: pattern4_with_continue.rs lines 350-378 for reference implementation
|
|
||||||
///
|
|
||||||
/// **Impact**: Low priority - Pattern 3 is test-only and works correctly with hardcoded values
|
|
||||||
///
|
|
||||||
/// Phase 195: Multi-carrier support - now includes both sum_final and count_final
|
|
||||||
const PATTERN3_K_EXIT_SUM_FINAL_ID: ValueId = ValueId(24); // Phase 195: Updated from ValueId(18)
|
|
||||||
const PATTERN3_K_EXIT_COUNT_FINAL_ID: ValueId = ValueId(25); // Phase 195: New count carrier
|
|
||||||
|
|
||||||
/// Phase 194: Detection function for Pattern 3
|
/// Phase 194: Detection function for Pattern 3
|
||||||
///
|
///
|
||||||
@ -106,62 +86,53 @@ impl MirBuilder {
|
|||||||
let mut join_value_space = JoinValueSpace::new();
|
let mut join_value_space = JoinValueSpace::new();
|
||||||
|
|
||||||
// Call Pattern 3 lowerer with preprocessed scope
|
// Call Pattern 3 lowerer with preprocessed scope
|
||||||
let join_module = match lower_loop_with_if_phi_pattern(ctx.loop_scope, &mut join_value_space) {
|
let (join_module, fragment_meta) = match lower_loop_with_if_phi_pattern(ctx.loop_scope, &mut join_value_space) {
|
||||||
Some(module) => module,
|
Ok(result) => result,
|
||||||
None => {
|
Err(e) => {
|
||||||
// Phase 195: Use unified trace
|
trace::trace().debug("pattern3", &format!("Pattern 3 lowerer failed: {}", e));
|
||||||
trace::trace().debug("pattern3", "Pattern 3 lowerer returned None");
|
return Err(format!("[cf_loop/pattern3] Lowering failed: {}", e));
|
||||||
return Ok(None);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let exit_meta = &fragment_meta.exit_meta;
|
||||||
|
|
||||||
|
trace::trace().debug(
|
||||||
|
"pattern3",
|
||||||
|
&format!("ExitMeta: {} exit values", exit_meta.exit_values.len())
|
||||||
|
);
|
||||||
|
for (carrier_name, join_value) in &exit_meta.exit_values {
|
||||||
|
trace::trace().debug(
|
||||||
|
"pattern3",
|
||||||
|
&format!(" {} → ValueId({})", carrier_name, join_value.0)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// Phase 195: Create boundary from context (multi-carrier support with backward compatibility)
|
// Phase 195: Create boundary from context (multi-carrier support with backward compatibility)
|
||||||
// Phase 201: Use JoinInlineBoundaryBuilder for clean construction
|
// Phase 201: Use JoinInlineBoundaryBuilder for clean construction
|
||||||
// Canonical Builder pattern - see docs/development/current/main/joinir-boundary-builder-pattern.md
|
// Canonical Builder pattern - see docs/development/current/main/joinir-boundary-builder-pattern.md
|
||||||
self.trace_varmap("pattern3_before_merge");
|
self.trace_varmap("pattern3_before_merge");
|
||||||
use crate::mir::join_ir::lowering::JoinInlineBoundaryBuilder;
|
use crate::mir::join_ir::lowering::JoinInlineBoundaryBuilder;
|
||||||
use crate::mir::join_ir::lowering::inline_boundary::LoopExitBinding;
|
|
||||||
|
|
||||||
// Phase 195: Build inputs and exit_bindings dynamically based on available carriers
|
// Phase 213: Use ExitMetaCollector for dynamic exit binding generation
|
||||||
let (join_inputs, host_inputs, exit_bindings) = if has_count {
|
// Note: ExitMetaCollector internally validates that all exit carriers in ExitMeta
|
||||||
// Multi-carrier: i, sum, count
|
// have corresponding variable_map entries. No additional validation needed here.
|
||||||
let count_var_id = count_carrier_opt.unwrap().host_id;
|
let exit_bindings = ExitMetaCollector::collect(
|
||||||
(
|
self,
|
||||||
vec![ValueId(0), ValueId(1), ValueId(2)], // JoinIR's main() parameters
|
exit_meta,
|
||||||
vec![ctx.loop_var_id, sum_var_id, count_var_id], // Host's loop variables
|
debug,
|
||||||
vec![
|
);
|
||||||
LoopExitBinding {
|
|
||||||
carrier_name: "sum".to_string(),
|
// Build join_inputs and host_inputs (retain existing logic)
|
||||||
join_exit_value: PATTERN3_K_EXIT_SUM_FINAL_ID, // ValueId(24)
|
let join_inputs = vec![ValueId(0), ValueId(1), ValueId(2)];
|
||||||
host_slot: sum_var_id,
|
let mut host_inputs = vec![ctx.loop_var_id, sum_var_id];
|
||||||
},
|
|
||||||
LoopExitBinding {
|
if has_count {
|
||||||
carrier_name: "count".to_string(),
|
host_inputs.push(count_carrier_opt.unwrap().host_id);
|
||||||
join_exit_value: PATTERN3_K_EXIT_COUNT_FINAL_ID, // ValueId(25)
|
|
||||||
host_slot: count_var_id,
|
|
||||||
}
|
|
||||||
]
|
|
||||||
)
|
|
||||||
} else {
|
} else {
|
||||||
// Single-carrier (backward compatibility): i, sum only
|
|
||||||
// Phase 195: JoinIR lowerer now always generates 3 parameters (i, sum, count)
|
|
||||||
// For backward compat, we create a dummy count variable that will be discarded
|
|
||||||
use crate::mir::builder::emission::constant;
|
use crate::mir::builder::emission::constant;
|
||||||
let dummy_count_id = constant::emit_void(self); // Use void as dummy value
|
let dummy_count_id = constant::emit_void(self);
|
||||||
|
host_inputs.push(dummy_count_id);
|
||||||
(
|
|
||||||
vec![ValueId(0), ValueId(1), ValueId(2)], // JoinIR's main() parameters (i, sum, count)
|
|
||||||
vec![ctx.loop_var_id, sum_var_id, dummy_count_id], // Host's loop variables (count is dummy)
|
|
||||||
vec![
|
|
||||||
LoopExitBinding {
|
|
||||||
carrier_name: "sum".to_string(),
|
|
||||||
join_exit_value: PATTERN3_K_EXIT_SUM_FINAL_ID, // ValueId(24)
|
|
||||||
host_slot: sum_var_id,
|
|
||||||
}
|
}
|
||||||
// Don't bind count in single-carrier mode - it's just discarded
|
|
||||||
]
|
|
||||||
)
|
|
||||||
};
|
|
||||||
|
|
||||||
let boundary = JoinInlineBoundaryBuilder::new()
|
let boundary = JoinInlineBoundaryBuilder::new()
|
||||||
.with_inputs(join_inputs, host_inputs)
|
.with_inputs(join_inputs, host_inputs)
|
||||||
|
|||||||
@ -110,7 +110,8 @@ pub fn lower_loop_with_conditional_phi_to_joinir(
|
|||||||
let mut join_value_space = JoinValueSpace::new();
|
let mut join_value_space = JoinValueSpace::new();
|
||||||
|
|
||||||
// Generate JoinIR module
|
// Generate JoinIR module
|
||||||
let _join_module = lower_loop_with_if_phi_pattern(placeholder_scope, &mut join_value_space)?;
|
// Phase 213: Updated to handle Result<(JoinModule, JoinFragmentMeta), String>
|
||||||
|
let _result = lower_loop_with_if_phi_pattern(placeholder_scope, &mut join_value_space).ok()?;
|
||||||
|
|
||||||
// Phase 188-Impl-3: Pattern 3 is now integrated via the router
|
// Phase 188-Impl-3: Pattern 3 is now integrated via the router
|
||||||
// This function delegates to loop_with_if_phi_minimal which generates JoinModule
|
// This function delegates to loop_with_if_phi_minimal which generates JoinModule
|
||||||
|
|||||||
@ -67,6 +67,7 @@
|
|||||||
//!
|
//!
|
||||||
//! Following the "80/20 rule" from CLAUDE.md - get it working first, generalize later.
|
//! Following the "80/20 rule" from CLAUDE.md - get it working first, generalize later.
|
||||||
|
|
||||||
|
use crate::mir::join_ir::lowering::carrier_info::{ExitMeta, JoinFragmentMeta};
|
||||||
use crate::mir::join_ir::lowering::join_value_space::JoinValueSpace;
|
use crate::mir::join_ir::lowering::join_value_space::JoinValueSpace;
|
||||||
use crate::mir::join_ir::lowering::loop_scope_shape::LoopScopeShape;
|
use crate::mir::join_ir::lowering::loop_scope_shape::LoopScopeShape;
|
||||||
use crate::mir::join_ir::{
|
use crate::mir::join_ir::{
|
||||||
@ -101,8 +102,8 @@ use crate::mir::join_ir::{
|
|||||||
///
|
///
|
||||||
/// # Returns
|
/// # Returns
|
||||||
///
|
///
|
||||||
/// * `Some(JoinModule)` - Successfully lowered to JoinIR
|
/// * `Ok((JoinModule, JoinFragmentMeta))` - Successfully lowered to JoinIR with exit metadata
|
||||||
/// * `None` - Pattern not matched (fallback to other lowerers)
|
/// * `Err(String)` - Pattern lowering failed with error message
|
||||||
///
|
///
|
||||||
/// # Boundary Contract
|
/// # Boundary Contract
|
||||||
///
|
///
|
||||||
@ -113,7 +114,7 @@ use crate::mir::join_ir::{
|
|||||||
pub(crate) fn lower_loop_with_if_phi_pattern(
|
pub(crate) fn lower_loop_with_if_phi_pattern(
|
||||||
_scope: LoopScopeShape,
|
_scope: LoopScopeShape,
|
||||||
join_value_space: &mut JoinValueSpace,
|
join_value_space: &mut JoinValueSpace,
|
||||||
) -> Option<JoinModule> {
|
) -> Result<(JoinModule, JoinFragmentMeta), String> {
|
||||||
// Phase 202-B: Use JoinValueSpace for unified ValueId allocation
|
// Phase 202-B: Use JoinValueSpace for unified ValueId allocation
|
||||||
// - Local region (1000+) ensures no collision with Param region (100-999)
|
// - Local region (1000+) ensures no collision with Param region (100-999)
|
||||||
let mut alloc_value = || join_value_space.alloc_local();
|
let mut alloc_value = || join_value_space.alloc_local();
|
||||||
@ -417,6 +418,14 @@ pub(crate) fn lower_loop_with_if_phi_pattern(
|
|||||||
// Set entry point
|
// Set entry point
|
||||||
join_module.entry = Some(main_id);
|
join_module.entry = Some(main_id);
|
||||||
|
|
||||||
|
// Phase 213: Build ExitMeta for dynamic exit binding generation
|
||||||
|
let mut exit_values = vec![];
|
||||||
|
exit_values.push(("sum".to_string(), sum_final));
|
||||||
|
exit_values.push(("count".to_string(), count_final)); // Phase 195: always include count
|
||||||
|
|
||||||
|
let exit_meta = ExitMeta::multiple(exit_values);
|
||||||
|
let fragment_meta = JoinFragmentMeta::carrier_only(exit_meta);
|
||||||
|
|
||||||
eprintln!("[joinir/pattern3] Generated JoinIR for Loop with If-Else PHI (Phase 195: multi-carrier)");
|
eprintln!("[joinir/pattern3] Generated JoinIR for Loop with If-Else PHI (Phase 195: multi-carrier)");
|
||||||
eprintln!("[joinir/pattern3] Functions: main, loop_step, k_exit");
|
eprintln!("[joinir/pattern3] Functions: main, loop_step, k_exit");
|
||||||
eprintln!("[joinir/pattern3] Carriers: i (counter), sum (accumulator), count (counter) [Phase 195]");
|
eprintln!("[joinir/pattern3] Carriers: i (counter), sum (accumulator), count (counter) [Phase 195]");
|
||||||
@ -424,5 +433,5 @@ pub(crate) fn lower_loop_with_if_phi_pattern(
|
|||||||
eprintln!("[joinir/pattern3] sum_new = (i % 2 == 1) ? sum+i : sum+0");
|
eprintln!("[joinir/pattern3] sum_new = (i % 2 == 1) ? sum+i : sum+0");
|
||||||
eprintln!("[joinir/pattern3] count_new = (i % 2 == 1) ? count+1 : count+0 [Phase 195]");
|
eprintln!("[joinir/pattern3] count_new = (i % 2 == 1) ? count+1 : count+0 [Phase 195]");
|
||||||
|
|
||||||
Some(join_module)
|
Ok((join_module, fragment_meta))
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user