docs(phase132): LLVM PHI命令順序バグ修正(指示書作成)
- 目標: PHI命令をBasicBlock先頭に配置(LLVM IR仕様準拠) - スコープ: Python layer (src/llvm_py/llvm_builder.py) のみ - 期待結果: 6/7 LLVM tests passing(Phase 131: 1/7から改善) - 6タスク: 設計doc、棚卸し、PhiPlacement実装、呼び出し整理、テスト、doc更新
This commit is contained in:
327
docs/development/current/main/phase132_llvm_phi_ordering.md
Normal file
327
docs/development/current/main/phase132_llvm_phi_ordering.md
Normal file
@ -0,0 +1,327 @@
|
||||
# Phase 132: LLVM finalize_phis の順序バグ修正
|
||||
|
||||
## 🎯 ゴール
|
||||
|
||||
LLVM backend における **「PHI 命令の配置順序バグ」を構造的に修正** する。
|
||||
|
||||
目的:
|
||||
- JoinIR→MIR→LLVM の意味論・制御構造は一切変えず、**「PHI はブロック先頭に並ぶ」という LLVM 規約** を満たす
|
||||
- 修正範囲は LLVM backend の finalize_phis 周辺に限定し、JoinIR/Ring0 には触らない
|
||||
- 代表ケース 6/7 で LLVM 実行が Rust VM と一致することを確認
|
||||
|
||||
```
|
||||
Phase 131: LLVM backend re-enable(1/7成功、PHI問題発見)✅
|
||||
↓
|
||||
Phase 132: PHI順序バグ構造的修正 ← ← ここ!
|
||||
↓
|
||||
Phase 133: 残りのLLVM統合タスク
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📋 スコープ(やること・やらないこと)
|
||||
|
||||
### ✅ やること
|
||||
- LLVM の PHI 命令生成・配置ロジック(finalize_phis 相当)を箱として整理
|
||||
- 常に **「ブロック先頭に PHI が並ぶ」** 順序にする
|
||||
- 代表ケース(Phase 130/131 で失敗していた 6/7)で LLVM 実行確認
|
||||
- docs に「PHI 順序の設計と仕様」を明記
|
||||
|
||||
### ❌ やらないこと
|
||||
- 新しい opcode の追加や、JoinIR/MIR の意味論変更
|
||||
- FileBox/Ring0 や logging まわりには触れない
|
||||
- LLVM backend 全体の最適化や再設計(PHI 順序に限定)
|
||||
|
||||
---
|
||||
|
||||
## 🏗️ 6 つのタスク
|
||||
|
||||
### Task 1: 設計ドキュメント作成
|
||||
|
||||
**ファイル**: `docs/development/current/main/phase132_llvm_phi_ordering.md`(このファイル)
|
||||
|
||||
**書く内容**:
|
||||
|
||||
#### LLVM の PHI 規則(簡潔版)
|
||||
- 各 BasicBlock では **「ラベル直後の連続した PHI 群」** が必須
|
||||
- PHI は同一ブロック内の他の命令より **前** に来なければならない
|
||||
- return や branch の **後** に PHI を置くのは仕様違反
|
||||
|
||||
#### 現状の問題点
|
||||
Phase 131 で観測した問題:
|
||||
|
||||
```llvm
|
||||
bb5:
|
||||
ret i64 %"ret_phi_16"
|
||||
%"ret_phi_16" = phi i64 [0, %"bb3"], [0, %"bb4"] ; ❌ エラー!PHIはretの前に必要
|
||||
}
|
||||
```
|
||||
|
||||
**原因**: `finalize_phis()` が「既存の末尾命令(terminator)の後ろに PHI を突っ込んでいる」
|
||||
|
||||
#### 目指す構造
|
||||
**PhiPlacement 責務箱** で「1ブロック内の (phi, non-phi) を再配置」する:
|
||||
|
||||
1. **分離**: 既存命令列を「仮想 PHI 命令」と「それ以外」に分離
|
||||
2. **クリア**: ブロックを一旦クリア
|
||||
3. **再構築**: 先に PHI 群を順に挿入、その後に非 PHI 命令を挿入
|
||||
4. **terminator 維持**: terminator(ret/br)は必ず非 PHI 群の末尾に維持
|
||||
|
||||
#### アルゴリズム方針(2案)
|
||||
|
||||
**案A**: 命令順序の後処理(推奨)
|
||||
- 各 LLVM BasicBlock について、生成後に命令順序を再配置
|
||||
- PHI 群 → 非 PHI 群 → terminator の順に並べ替え
|
||||
|
||||
**案B**: 生成時点での順序保証
|
||||
- PHI を生成する時点で「必ず insert_at_beginning 的な API」を使う
|
||||
- 生成タイミングを制御して順序を保証
|
||||
|
||||
**Phase 132 では案A を採用**(実装が明確で、既存コードへの影響が小さい)
|
||||
|
||||
---
|
||||
|
||||
### Task 2: 既存 finalize_phis 実装の棚卸し
|
||||
|
||||
**対象ファイル**: `src/llvm_py/llvm_builder.py`(Phase 131 で特定済み)
|
||||
|
||||
**やること**:
|
||||
|
||||
1. **finalize_phis 関数の詳細確認**:
|
||||
```bash
|
||||
rg "def finalize_phis" src/llvm_py/
|
||||
```
|
||||
- 約100行の関数
|
||||
- どのタイミングで LLVM IR に PHI を挿入しているか確認
|
||||
- どのブロックに対して、どの API で PHI を追加しているか記録
|
||||
|
||||
2. **PHI 情報の元データ確認**:
|
||||
- MIR JSON から PHI 情報を取得している部分を特定
|
||||
- Builder の一時バッファ(pending phi list 等)の所在を確認
|
||||
|
||||
3. **呼び出し経路の確認**:
|
||||
- どのフェーズで finalize_phis が呼ばれているか
|
||||
- 複数回呼ばれていないか(2重呼び出しの危険性)
|
||||
|
||||
---
|
||||
|
||||
### Task 3: PhiPlacement 責務箱の実装
|
||||
|
||||
**方針**: finalize_phis の「命令順序入れ替え責務」を専用の関数/クラスに閉じ込める
|
||||
|
||||
**実装箇所**: `src/llvm_py/phi_placement.py`(新規)または `llvm_builder.py` 内の関数
|
||||
|
||||
**責務**:
|
||||
- 引数: 単一の LLVM BasicBlock(または block + pending phi list)
|
||||
- 動作:
|
||||
- そのブロック内の命令列を走査し、「PHI 相当」と「それ以外」を分類
|
||||
- 新しい命令順序(PHI 群 → 非 PHI 群)に組み直す
|
||||
- **PHI の内容は一切触らない。順序だけ直す。**
|
||||
|
||||
**実装パターン**:
|
||||
|
||||
```python
|
||||
def reorder_phi_instructions(block, phi_nodes):
|
||||
"""
|
||||
LLVM BasicBlock 内の命令順序を PHI-first に並べ替え
|
||||
|
||||
Args:
|
||||
block: LLVM BasicBlock
|
||||
phi_nodes: このblockに属するPHI命令のリスト
|
||||
|
||||
Returns:
|
||||
再配置されたblock
|
||||
"""
|
||||
# 1. 既存命令を分類
|
||||
non_phi_instructions = []
|
||||
terminator = None
|
||||
|
||||
for instr in block.instructions:
|
||||
if is_terminator(instr):
|
||||
terminator = instr
|
||||
elif not is_phi(instr):
|
||||
non_phi_instructions.append(instr)
|
||||
|
||||
# 2. Block をクリア(または新しいblockを作成)
|
||||
new_block = create_empty_block(block.name)
|
||||
|
||||
# 3. PHI群を先頭に挿入
|
||||
for phi in phi_nodes:
|
||||
new_block.append(phi)
|
||||
|
||||
# 4. 非PHI命令を挿入
|
||||
for instr in non_phi_instructions:
|
||||
new_block.append(instr)
|
||||
|
||||
# 5. Terminator を最後に挿入
|
||||
if terminator:
|
||||
new_block.append(terminator)
|
||||
|
||||
return new_block
|
||||
```
|
||||
|
||||
**注意点**:
|
||||
- llvmlite の API に応じて実装を調整
|
||||
- 既存の finalize_phis から「PHI 生成ロジック」と「配置ロジック」を分離
|
||||
- 生成ロジックはそのまま、配置ロジックだけを新関数に移す
|
||||
|
||||
---
|
||||
|
||||
### Task 4: finalize_phis 呼び出し経路の整理
|
||||
|
||||
**やること**:
|
||||
|
||||
1. **呼び出し位置の確認**:
|
||||
```bash
|
||||
rg "finalize_phis" src/llvm_py/
|
||||
```
|
||||
- LLVM lowering のどのフェーズで呼ばれているか
|
||||
- 関数生成の最後か、ブロック生成の途中か
|
||||
|
||||
2. **ルール設定**:
|
||||
- 各関数(または各 BasicBlock)で、PHI 生成が完了した後、**必ず PhiPlacement を通す**
|
||||
- 2重に呼ばない/途中で呼びかけて順序を壊さないように、呼び出し位置を一箇所にまとめる
|
||||
|
||||
3. **位置付け**:
|
||||
- JoinIR / MIR 側には一切触れず、**「LLVM 出力直前の最後の整形処理」** として位置付ける
|
||||
|
||||
---
|
||||
|
||||
### Task 5: テスト追加(LLVM 専用)
|
||||
|
||||
**代表ケース**:
|
||||
|
||||
Phase 130/131 で「Rust VM OK, LLVM NG」だったケース:
|
||||
- `local_tests/phase123_simple_if.hako`(シンプルな if)
|
||||
- `local_tests/phase123_while_loop.hako`(while loop)
|
||||
- `apps/tests/loop_min_while.hako`(最小ループ)
|
||||
- `apps/tests/joinir_if_select_simple.hako`(IfSelect)
|
||||
|
||||
**テスト戦略**:
|
||||
|
||||
1. **LLVM IR 検証**(可能なら):
|
||||
- MIR → LLVM IR 生成時に、各ブロックの PHI が先頭に並んでいるかチェック
|
||||
- LLVM IR の text dump をパースして簡易検証
|
||||
|
||||
2. **実行結果検証**(必須):
|
||||
```bash
|
||||
# 各テストケースで Rust VM と LLVM の両方を実行
|
||||
./target/release/nyash --backend vm local_tests/phase123_simple_if.hako
|
||||
LLVM_SYS_180_PREFIX=$(llvm-config-18 --prefix) \
|
||||
NYASH_LLVM_USE_HARNESS=1 \
|
||||
./target/release/nyash --backend llvm local_tests/phase123_simple_if.hako
|
||||
|
||||
# 結果が一致することを確認
|
||||
```
|
||||
|
||||
3. **複雑なケース**:
|
||||
- loop + if など、PHI 構造が複雑なケース 1 本を確認
|
||||
- 例: `apps/tests/joinir_min_loop.hako`
|
||||
|
||||
---
|
||||
|
||||
### Task 6: ドキュメント & CURRENT_TASK 更新
|
||||
|
||||
**やること**:
|
||||
|
||||
1. **このファイル(phase132_llvm_phi_ordering.md)の末尾に追記**:
|
||||
```markdown
|
||||
## Phase 132 実装結果
|
||||
|
||||
### 修正ファイル
|
||||
- `src/llvm_py/llvm_builder.py`: finalize_phis() 修正
|
||||
- `src/llvm_py/phi_placement.py`: 新規作成(または llvm_builder.py 内の関数)
|
||||
|
||||
### テスト結果
|
||||
| ケース | Rust VM | LLVM (Phase 131) | LLVM (Phase 132) |
|
||||
|--------|---------|------------------|------------------|
|
||||
| phase123_simple_if.hako | ✅ | ❌ | ✅ |
|
||||
| phase123_while_loop.hako | ✅ | ❌ | ✅ |
|
||||
| loop_min_while.hako | ✅ | ❌ | ✅ |
|
||||
| joinir_if_select_simple.hako | ✅ | ❌ | ✅ |
|
||||
|
||||
### 成果
|
||||
- PHI 順序バグの構造的修正完了
|
||||
- LLVM backend の基本整合が取れた
|
||||
- 6/7 テストが LLVM で実行成功(残り1つは ConsoleBox 問題)
|
||||
```
|
||||
|
||||
2. **CURRENT_TASK.md 更新**:
|
||||
```markdown
|
||||
### Phase 132: LLVM PHI 命令順序バグ修正 ✅
|
||||
|
||||
**完了内容**:
|
||||
- finalize_phis() の構造的リファクタリング
|
||||
- PHI 命令をブロック先頭に配置する PhiPlacement 実装
|
||||
- 代表ケース 6/7 で LLVM 実行成功
|
||||
|
||||
**修正箇所**:
|
||||
- src/llvm_py/llvm_builder.py: PHI生成・配置ロジック分離
|
||||
- src/llvm_py/phi_placement.py: 新規作成(または関数追加)
|
||||
|
||||
**テスト結果**:
|
||||
- 修正前: LLVM 1/7 実行可能
|
||||
- 修正後: LLVM 6/7 実行可能(PHI順序問題解決)
|
||||
|
||||
**成果**:
|
||||
- JoinIR → LLVM 経路の基本動作確認完了
|
||||
- Phase 133 で ConsoleBox 統合を完了すれば 7/7 達成
|
||||
|
||||
**次フェーズ**: Phase 133 - ConsoleBox LLVM 統合 & 残りタスク
|
||||
```
|
||||
|
||||
3. **30-Backlog.md 更新**:
|
||||
```markdown
|
||||
### Phase 133: ConsoleBox LLVM 統合 & JoinIR→LLVM 完成
|
||||
|
||||
Phase 132 で PHI 順序問題解決、残りタスク:
|
||||
- ConsoleBox の Rust VM 登録確認
|
||||
- ConsoleBox の LLVM 統合(println/log 外部関数)
|
||||
- 全7テストケースで LLVM 実行成功確認
|
||||
|
||||
完了条件:
|
||||
- ✅ 7/7 テストが Rust VM と LLVM で実行成功
|
||||
- ✅ JoinIR → LLVM 第3章クローズ
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ✅ 完成チェックリスト(Phase 132)
|
||||
|
||||
- [ ] LLVM PHI 規則の設計ドキュメント作成
|
||||
- [ ] finalize_phis() 実装の詳細確認(約100行)
|
||||
- [ ] PhiPlacement 責務箱の実装(新関数 or 新ファイル)
|
||||
- [ ] PHI 命令をブロック先頭に配置するロジック実装
|
||||
- [ ] finalize_phis 呼び出し経路の整理
|
||||
- [ ] 代表ケース 4-6 本で LLVM 実行成功確認
|
||||
- [ ] phase132_llvm_phi_ordering.md に実装結果追記
|
||||
- [ ] CURRENT_TASK.md & Backlog 更新
|
||||
- [ ] git commit で記録
|
||||
|
||||
---
|
||||
|
||||
## 所要時間
|
||||
|
||||
**3〜4 時間程度**
|
||||
|
||||
- Task 1-2 (設計ドキュメント & 棚卸し): 1時間
|
||||
- Task 3 (PhiPlacement 実装): 1.5時間
|
||||
- Task 4-5 (呼び出し整理 & テスト): 1時間
|
||||
- Task 6 (ドキュメント更新): 30分
|
||||
|
||||
---
|
||||
|
||||
## 次のステップ
|
||||
|
||||
**Phase 133: ConsoleBox LLVM 統合 & JoinIR→LLVM 完成**
|
||||
- Phase 132 で PHI 問題解決後、残りの ConsoleBox 統合
|
||||
- 全7テストケースで LLVM 実行成功
|
||||
- JoinIR → LLVM 第3章クローズ
|
||||
|
||||
---
|
||||
|
||||
## 進捗
|
||||
|
||||
- ✅ Phase 131: LLVM backend re-enable & PHI 問題発見(完了)
|
||||
- 🎯 Phase 132: LLVM PHI 命令順序バグ修正(← **現在のフェーズ**)
|
||||
- 📋 Phase 133: ConsoleBox LLVM 統合 & 完成(予定)
|
||||
Reference in New Issue
Block a user