2025-12-09 14:07:42 +09:00
|
|
|
|
# Phase 196: Select 展開/変換バグ 調査 & 修正
|
|
|
|
|
|
|
|
|
|
|
|
**Status**: Ready for Implementation
|
|
|
|
|
|
**Date**: 2025-12-09
|
|
|
|
|
|
**Prerequisite**: Phase 195 complete (Lowerer side, blocked by Select bug)
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 目的
|
|
|
|
|
|
|
|
|
|
|
|
**JoinIR→MIR の Select 展開処理で発生している既存バグ**を特定・修正する。
|
|
|
|
|
|
|
|
|
|
|
|
**問題**:
|
|
|
|
|
|
- JoinIR 上では正しい PHI が生成されている
|
|
|
|
|
|
- MIR 変換時に PHI inputs が undefined ValueId を参照する
|
|
|
|
|
|
|
|
|
|
|
|
**スコープ**:
|
|
|
|
|
|
- ✅ bridge 側(join_ir_vm_bridge / merge ライン)のみ修正
|
|
|
|
|
|
- ❌ Pattern3/multi-carrier など パターン側は触らない(Phase 195 で完了)
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## Task 196-1: 最小再現ケースと期待形の固定(doc + デバッグ)
|
|
|
|
|
|
|
|
|
|
|
|
### 目標
|
|
|
|
|
|
**最小再現ケースを phase195_sum_count.hako に固定**し、「正しい構造 vs 壊れた構造」を 1 枚絵レベルまで落とす。
|
|
|
|
|
|
|
|
|
|
|
|
### 対象ファイル
|
|
|
|
|
|
- `apps/tests/phase195_sum_count.hako`(既存)
|
|
|
|
|
|
|
|
|
|
|
|
### 実行手順
|
|
|
|
|
|
|
|
|
|
|
|
#### 1. JoinIR 側の期待される構造を記録
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
# JoinIR debug trace を取得
|
|
|
|
|
|
NYASH_JOINIR_CORE=1 NYASH_JOINIR_DEBUG=1 ./target/release/hakorune apps/tests/phase195_sum_count.hako 2>&1 > /tmp/joinir_trace.log
|
|
|
|
|
|
|
|
|
|
|
|
# JoinIR 上の Select/PHI を確認
|
|
|
|
|
|
grep -E "Select|handle_select|Phi" /tmp/joinir_trace.log
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
**記録する情報**:
|
|
|
|
|
|
- Select 命令の dst ValueId
|
|
|
|
|
|
- PHI の inputs: `[(BasicBlockId, ValueId), (BasicBlockId, ValueId)]`
|
|
|
|
|
|
- 各 BasicBlockId が何を表すか(then/else/merge)
|
|
|
|
|
|
|
|
|
|
|
|
**例**(Phase 195 での観測結果):
|
|
|
|
|
|
```
|
|
|
|
|
|
JoinIR (正しい):
|
|
|
|
|
|
Select dst=ValueId(20)
|
|
|
|
|
|
PHI: ValueId(20) = phi [(BasicBlockId(3), ValueId(14)), (BasicBlockId(4), ValueId(18))]
|
|
|
|
|
|
|
|
|
|
|
|
ValueId(14): sum + i (then branch)
|
|
|
|
|
|
ValueId(18): sum + 0 (else branch)
|
|
|
|
|
|
BasicBlockId(3): then block
|
|
|
|
|
|
BasicBlockId(4): else block
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
#### 2. MIR 側で生成されている壊れた構造を記録
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
# MIR dump を取得
|
|
|
|
|
|
./target/release/hakorune --dump-mir apps/tests/phase195_sum_count.hako 2>&1 > /tmp/mir_dump.log
|
|
|
|
|
|
|
|
|
|
|
|
# 壊れた PHI を確認
|
|
|
|
|
|
grep -A5 "phi" /tmp/mir_dump.log
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
**記録する情報**:
|
|
|
|
|
|
- 壊れた PHI 命令の行番号
|
|
|
|
|
|
- PHI inputs の ValueId(%28, %32 等)が undefined か確認
|
|
|
|
|
|
- どの BasicBlock が関与しているか
|
|
|
|
|
|
|
|
|
|
|
|
**例**(Phase 195 での観測結果):
|
|
|
|
|
|
```
|
|
|
|
|
|
MIR (壊れている):
|
|
|
|
|
|
bb10:
|
|
|
|
|
|
%27 = phi [%28, bb8], [%32, bb9]
|
|
|
|
|
|
|
|
|
|
|
|
問題: %28, %32 は bb8, bb9 で定義されていない(undefined)
|
|
|
|
|
|
bb8, bb9 は単に jump のみ(値を生成していない)
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
#### 3. 原因 Select の特定
|
|
|
|
|
|
|
|
|
|
|
|
**どの Select が壊れているか**を 1 ヶ所に絞る:
|
|
|
|
|
|
- JoinIR で ValueId(20) として生成された Select
|
|
|
|
|
|
- MIR で %27 として出現する PHI
|
|
|
|
|
|
|
|
|
|
|
|
### 成果物
|
|
|
|
|
|
|
|
|
|
|
|
**ファイル**: `docs/development/current/main/phase196-select-bug-analysis.md`
|
|
|
|
|
|
|
|
|
|
|
|
```markdown
|
|
|
|
|
|
# Phase 196: Select Bug Analysis
|
|
|
|
|
|
|
|
|
|
|
|
## Minimal Reproduction Case
|
|
|
|
|
|
|
|
|
|
|
|
**File**: `apps/tests/phase195_sum_count.hako`
|
|
|
|
|
|
|
|
|
|
|
|
## Expected Structure (JoinIR)
|
|
|
|
|
|
|
|
|
|
|
|
### Select Instruction
|
|
|
|
|
|
- dst: ValueId(20)
|
|
|
|
|
|
- condition: ValueId(19) // i > 2
|
|
|
|
|
|
- then_value: ValueId(14) // sum + i
|
|
|
|
|
|
- else_value: ValueId(18) // sum + 0
|
|
|
|
|
|
|
|
|
|
|
|
### PHI Instruction (Correct)
|
|
|
|
|
|
```
|
|
|
|
|
|
ValueId(20) = phi [
|
|
|
|
|
|
(BasicBlockId(3), ValueId(14)), // then: sum + i
|
|
|
|
|
|
(BasicBlockId(4), ValueId(18)) // else: sum + 0
|
|
|
|
|
|
]
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
## Actual Structure (MIR - Broken)
|
|
|
|
|
|
|
|
|
|
|
|
### PHI Instruction (bb10)
|
|
|
|
|
|
```
|
|
|
|
|
|
%27 = phi [%28, bb8], [%32, bb9]
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
**Problem**:
|
|
|
|
|
|
- %28 is NOT defined in bb8 (bb8 only contains jump)
|
|
|
|
|
|
- %32 is NOT defined in bb9 (bb9 only contains jump)
|
|
|
|
|
|
- Expected: %27 = phi [%14_mapped, bb8], [%18_mapped, bb9]
|
|
|
|
|
|
|
|
|
|
|
|
## Root Cause Hypothesis
|
|
|
|
|
|
|
|
|
|
|
|
1. PHI inputs use wrong ValueIds (not the then/else values)
|
|
|
|
|
|
2. Block ID mapping corruption
|
|
|
|
|
|
3. ValueId remapping issue (JoinIR → MIR)
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## Task 196-2: Select 展開経路の責務整理(コード読むだけ)
|
|
|
|
|
|
|
|
|
|
|
|
### 目標
|
|
|
|
|
|
**Select 展開の責務位置を特定**し、どこで「Branch + then/else + Phi」に変換されているかを明確化する。
|
|
|
|
|
|
|
|
|
|
|
|
### 対象ファイル(読み取りのみ)
|
|
|
|
|
|
|
|
|
|
|
|
1. **`src/mir/join_ir_vm_bridge/convert.rs`**:
|
|
|
|
|
|
- JoinIR → MIR 変換の entry point
|
|
|
|
|
|
- Select 命令の処理箇所を探す
|
|
|
|
|
|
|
|
|
|
|
|
2. **`src/mir/builder/control_flow/joinir/merge/instruction_rewriter.rs`**:
|
|
|
|
|
|
- ExitLine / PHI 周りの書き換え処理
|
|
|
|
|
|
- Select 関連の rewrite logic を確認
|
|
|
|
|
|
|
|
|
|
|
|
3. **`src/mir/join_ir/joinir_block.rs`**(Phase 195 で言及された):
|
|
|
|
|
|
- `handle_select` 関数の実装
|
|
|
|
|
|
- Select → 3 blocks + 1 PHI の展開ロジック
|
|
|
|
|
|
|
|
|
|
|
|
### 調査内容
|
|
|
|
|
|
|
|
|
|
|
|
#### 1. Select 展開の entry point を特定
|
|
|
|
|
|
|
|
|
|
|
|
**質問**:
|
|
|
|
|
|
- どの関数が Select 命令を受け取るか?
|
|
|
|
|
|
- Select → Branch + then/else に変換する箇所はどこか?
|
|
|
|
|
|
|
|
|
|
|
|
**記録する情報**:
|
|
|
|
|
|
```markdown
|
|
|
|
|
|
## Select Expansion Entry Point
|
|
|
|
|
|
|
|
|
|
|
|
**File**: src/mir/join_ir/joinir_block.rs
|
|
|
|
|
|
**Function**: `handle_select` (line XXX)
|
|
|
|
|
|
|
|
|
|
|
|
**Responsibilities**:
|
|
|
|
|
|
1. Create 3 blocks: then, else, merge
|
|
|
|
|
|
2. Generate PHI in merge block
|
|
|
|
|
|
3. Map JoinIR ValueIds to MIR ValueIds
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
#### 2. PHI inputs の生成箇所を特定
|
|
|
|
|
|
|
|
|
|
|
|
**質問**:
|
|
|
|
|
|
- PHI の inputs (ValueId, BasicBlockId) はどこで決定されるか?
|
|
|
|
|
|
- JoinIR の ValueId → MIR の ValueId への変換はどこで行われるか?
|
|
|
|
|
|
|
|
|
|
|
|
**記録する情報**:
|
|
|
|
|
|
```markdown
|
|
|
|
|
|
## PHI Input Generation
|
|
|
|
|
|
|
|
|
|
|
|
**Location**: handle_select function (line YYY)
|
|
|
|
|
|
|
|
|
|
|
|
**Current Logic**:
|
|
|
|
|
|
```rust
|
|
|
|
|
|
let phi_inputs = vec![
|
|
|
|
|
|
(then_block_id, ???), // どの ValueId を使っているか
|
|
|
|
|
|
(else_block_id, ???),
|
|
|
|
|
|
];
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
**Remapper Usage**:
|
|
|
|
|
|
- [ ] Uses remapper.get_value() ← CORRECT
|
|
|
|
|
|
- [ ] Uses raw JoinIR ValueId ← INCORRECT
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
#### 3. Block 作成と再利用の確認
|
|
|
|
|
|
|
|
|
|
|
|
**質問**:
|
|
|
|
|
|
- 3 blocks (then, else, merge) はどう作成されるか?
|
|
|
|
|
|
- 既存 block との衝突はないか?(Phase 33-20 の教訓)
|
|
|
|
|
|
|
|
|
|
|
|
**記録する情報**:
|
|
|
|
|
|
```markdown
|
|
|
|
|
|
## Block Creation
|
|
|
|
|
|
|
|
|
|
|
|
**then_block**:
|
|
|
|
|
|
- Creation: `builder.create_block()` or reuse?
|
|
|
|
|
|
- Content: then_value computation
|
|
|
|
|
|
|
|
|
|
|
|
**else_block**:
|
|
|
|
|
|
- Creation: `builder.create_block()` or reuse?
|
|
|
|
|
|
- Content: else_value computation
|
|
|
|
|
|
|
|
|
|
|
|
**merge_block**:
|
|
|
|
|
|
- Creation: `builder.create_block()`
|
|
|
|
|
|
- Content: PHI instruction only
|
|
|
|
|
|
- Potential issue: Overwrite existing block?
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 成果物
|
|
|
|
|
|
|
|
|
|
|
|
**phase196-select-bug-analysis.md に追記**:
|
|
|
|
|
|
```markdown
|
|
|
|
|
|
## Select Expansion Code Path
|
|
|
|
|
|
|
|
|
|
|
|
### Responsibility Location
|
|
|
|
|
|
|
|
|
|
|
|
**Primary Function**: `src/mir/join_ir/joinir_block.rs::handle_select`
|
|
|
|
|
|
|
|
|
|
|
|
**Flow**:
|
|
|
|
|
|
1. Receive Select instruction (dst, cond, then_val, else_val)
|
|
|
|
|
|
2. Create 3 blocks (then, else, merge)
|
|
|
|
|
|
3. Emit then_value in then_block
|
|
|
|
|
|
4. Emit else_value in else_block
|
|
|
|
|
|
5. Create PHI in merge_block with inputs: [(then_block, then_val), (else_block, else_val)]
|
|
|
|
|
|
6. Return merge_block
|
|
|
|
|
|
|
|
|
|
|
|
### Current Implementation Issues (Hypothesis)
|
|
|
|
|
|
|
|
|
|
|
|
- [ ] PHI inputs use wrong ValueIds (need verification)
|
|
|
|
|
|
- [ ] Block ID mapping corruption (need verification)
|
|
|
|
|
|
- [ ] ValueId remapping not applied (need verification)
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## Task 196-3: 修正方針の決定(箱は増やさない)
|
|
|
|
|
|
|
|
|
|
|
|
### 目標
|
|
|
|
|
|
**3つの修正候補から原因を特定**し、最小限の変更で修正する。
|
|
|
|
|
|
|
|
|
|
|
|
### 修正候補
|
|
|
|
|
|
|
|
|
|
|
|
#### 候補 1: PHI inputs の ValueId チェック
|
|
|
|
|
|
|
|
|
|
|
|
**仮説**: PHI inputs に間違った ValueId を使っている
|
|
|
|
|
|
|
|
|
|
|
|
**確認方法**:
|
|
|
|
|
|
```rust
|
|
|
|
|
|
// handle_select の中で PHI inputs を作る箇所を確認
|
|
|
|
|
|
let phi_inputs = vec![
|
|
|
|
|
|
(then_block_id, then_value_id), // ← これが正しい ValueId か?
|
|
|
|
|
|
(else_block_id, else_value_id),
|
|
|
|
|
|
];
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
**期待される修正**:
|
|
|
|
|
|
```rust
|
|
|
|
|
|
// 正しい形: then/else の計算結果を使う
|
|
|
|
|
|
let then_result = emit_then_value(...)?; // ← この ValueId
|
|
|
|
|
|
let else_result = emit_else_value(...)?; // ← この ValueId
|
|
|
|
|
|
|
|
|
|
|
|
let phi_inputs = vec![
|
|
|
|
|
|
(then_block_id, then_result), // ← emit した結果を使う
|
|
|
|
|
|
(else_block_id, else_result),
|
|
|
|
|
|
];
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
#### 候補 2: ブロック再利用 vs 上書き問題
|
|
|
|
|
|
|
|
|
|
|
|
**仮説**: BasicBlockId の HashMap 上書きで PHI が消える(Phase 33-20 と同じ)
|
|
|
|
|
|
|
|
|
|
|
|
**確認方法**:
|
|
|
|
|
|
```rust
|
|
|
|
|
|
// blocks HashMap に直接 insert していないか確認
|
|
|
|
|
|
mir_builder.blocks.insert(merge_block_id, merge_block); // ← 危険
|
|
|
|
|
|
|
|
|
|
|
|
// 既存ブロックがある場合は「取り出して更新」パターンか確認
|
|
|
|
|
|
let mut block = mir_builder.blocks.remove(&block_id).unwrap();
|
|
|
|
|
|
block.instructions.push(phi_inst);
|
|
|
|
|
|
mir_builder.blocks.insert(block_id, block); // ← 安全
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
**期待される修正**:
|
|
|
|
|
|
- HashMap を上書きせず、既存ブロックに追記する形に修正
|
|
|
|
|
|
|
|
|
|
|
|
#### 候補 3: JoinInlineBoundary remapper の使い方
|
|
|
|
|
|
|
|
|
|
|
|
**仮説**: remap 前の ValueId を PHI inputs に直接使っている
|
|
|
|
|
|
|
|
|
|
|
|
**確認方法**:
|
|
|
|
|
|
```rust
|
|
|
|
|
|
// remapper を使っているか確認
|
|
|
|
|
|
let phi_inputs = vec![
|
|
|
|
|
|
(then_block_id, join_value_id), // ← JoinIR の ValueId そのまま(NG)
|
|
|
|
|
|
(else_block_id, join_value_id),
|
|
|
|
|
|
];
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
**期待される修正**:
|
|
|
|
|
|
```rust
|
|
|
|
|
|
// remapper 経由で MIR ValueId に変換
|
|
|
|
|
|
let then_mir_value = remapper.get_value(join_then_value)
|
|
|
|
|
|
.ok_or_else(|| format!("ValueId not in remapper: {:?}", join_then_value))?;
|
|
|
|
|
|
let else_mir_value = remapper.get_value(join_else_value)
|
|
|
|
|
|
.ok_or_else(|| format!("ValueId not in remapper: {:?}", join_else_value))?;
|
|
|
|
|
|
|
|
|
|
|
|
let phi_inputs = vec![
|
|
|
|
|
|
(then_block_id, then_mir_value), // ← remap 済み ValueId
|
|
|
|
|
|
(else_block_id, else_mir_value),
|
|
|
|
|
|
];
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 実装手順
|
|
|
|
|
|
|
|
|
|
|
|
1. **Task 196-2 の調査結果を元に原因を絞る**
|
|
|
|
|
|
2. **1つの候補に集中して修正**(複数同時にやらない)
|
|
|
|
|
|
3. **E2E テストで確認**(phase195_sum_count.hako)
|
|
|
|
|
|
4. **ダメなら次の候補へ**(Fail-Fast)
|
|
|
|
|
|
|
|
|
|
|
|
### 設計原則
|
|
|
|
|
|
|
|
|
|
|
|
- **箱は増やさない**: 既存 Select 展開ロジックの中だけを修正
|
|
|
|
|
|
- **最小限の変更**: 1箇所だけ直す(複数箇所の同時変更は避ける)
|
|
|
|
|
|
- **明示的エラー**: remapper.get_value() が None なら明示的に失敗
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## Task 196-4: E2E 再検証 & 退行チェック
|
|
|
|
|
|
|
|
|
|
|
|
### 目標
|
|
|
|
|
|
修正後、**phase195_sum_count.hako が動作**し、**既存テストが退行しない**ことを確認。
|
|
|
|
|
|
|
|
|
|
|
|
### テストケース
|
|
|
|
|
|
|
|
|
|
|
|
#### 1. Multi-carrier P3 (Phase 195)
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
# Phase 195 の multi-carrier テスト
|
|
|
|
|
|
NYASH_JOINIR_CORE=1 ./target/release/hakorune apps/tests/phase195_sum_count.hako
|
|
|
|
|
|
|
|
|
|
|
|
# Expected: 72 (sum=7, count=2)
|
|
|
|
|
|
# Verify: No SSA-undef error, No [joinir/freeze]
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
#### 2. Single-carrier P3 (既存)
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
# 既存の単一キャリア P3 テスト
|
|
|
|
|
|
NYASH_JOINIR_CORE=1 ./target/release/hakorune apps/tests/loop_if_phi.hako
|
|
|
|
|
|
|
|
|
|
|
|
# Expected: sum=9 (または既存の期待値)
|
|
|
|
|
|
# Verify: No regression
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
#### 3. Pattern 1/2/4 代表テスト
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
# Pattern 1: Simple while
|
|
|
|
|
|
NYASH_JOINIR_CORE=1 ./target/release/hakorune apps/tests/loop_min_while.hako
|
|
|
|
|
|
|
|
|
|
|
|
# Pattern 2: Break
|
|
|
|
|
|
NYASH_JOINIR_CORE=1 ./target/release/hakorune apps/tests/joinir_min_loop.hako
|
|
|
|
|
|
|
|
|
|
|
|
# Pattern 4: Continue
|
|
|
|
|
|
NYASH_JOINIR_CORE=1 ./target/release/hakorune apps/tests/loop_continue_pattern4.hako
|
|
|
|
|
|
|
|
|
|
|
|
# Verify: All pass with expected values
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 成功基準
|
|
|
|
|
|
|
|
|
|
|
|
- [ ] phase195_sum_count.hako → 72 ✅
|
|
|
|
|
|
- [ ] loop_if_phi.hako → 期待値(退行なし)✅
|
|
|
|
|
|
- [ ] P1/P2/P4 代表テスト → 退行なし ✅
|
|
|
|
|
|
- [ ] SSA-undef / PHI エラーなし ✅
|
|
|
|
|
|
- [ ] [joinir/freeze] なし ✅
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## Task 196-5: ドキュメント更新
|
|
|
|
|
|
|
|
|
|
|
|
### 1. phase196-select-bug-analysis.md に Before/After 追記
|
|
|
|
|
|
|
|
|
|
|
|
```markdown
|
|
|
|
|
|
## Fix Applied
|
|
|
|
|
|
|
|
|
|
|
|
### Root Cause
|
|
|
|
|
|
|
|
|
|
|
|
[Determined root cause from candidates 1-3]
|
|
|
|
|
|
|
|
|
|
|
|
### Code Change
|
|
|
|
|
|
|
|
|
|
|
|
**File**: src/mir/join_ir/joinir_block.rs (line XXX)
|
|
|
|
|
|
|
|
|
|
|
|
**Before**:
|
|
|
|
|
|
```rust
|
|
|
|
|
|
let phi_inputs = vec![
|
|
|
|
|
|
(then_block_id, wrong_value_id),
|
|
|
|
|
|
(else_block_id, wrong_value_id),
|
|
|
|
|
|
];
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
**After**:
|
|
|
|
|
|
```rust
|
|
|
|
|
|
let then_mir_value = remapper.get_value(join_then_value)?;
|
|
|
|
|
|
let else_mir_value = remapper.get_value(join_else_value)?;
|
|
|
|
|
|
let phi_inputs = vec![
|
|
|
|
|
|
(then_block_id, then_mir_value),
|
|
|
|
|
|
(else_block_id, else_mir_value),
|
|
|
|
|
|
];
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### MIR PHI (After Fix)
|
|
|
|
|
|
|
|
|
|
|
|
**Before**:
|
|
|
|
|
|
```
|
|
|
|
|
|
bb10:
|
|
|
|
|
|
%27 = phi [%28, bb8], [%32, bb9] // %28, %32 undefined
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
**After**:
|
|
|
|
|
|
```
|
|
|
|
|
|
bb10:
|
|
|
|
|
|
%27 = phi [%14, bb8], [%18, bb9] // %14, %18 correctly defined
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### Test Results
|
|
|
|
|
|
|
|
|
|
|
|
- phase195_sum_count.hako: 72 ✅
|
|
|
|
|
|
- loop_if_phi.hako: sum=9 ✅
|
|
|
|
|
|
- No regressions ✅
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 2. CURRENT_TASK.md 更新
|
|
|
|
|
|
|
|
|
|
|
|
```markdown
|
|
|
|
|
|
## Phase 196: Select 展開/変換バグ調査&修正(完了: 2025-12-XX)
|
|
|
|
|
|
|
|
|
|
|
|
**目的**: JoinIR→MIR の Select 展開処理バグを修正
|
|
|
|
|
|
|
|
|
|
|
|
**実装内容**:
|
|
|
|
|
|
- 196-1: 最小再現ケース固定(phase195_sum_count.hako)
|
|
|
|
|
|
- 196-2: Select 展開経路の責務特定(joinir_block.rs::handle_select)
|
|
|
|
|
|
- 196-3: 修正実装(PHI inputs に remapper 適用)
|
|
|
|
|
|
- 196-4: E2E 再検証 + 退行チェック(全テスト PASS)
|
|
|
|
|
|
|
|
|
|
|
|
**成果**:
|
|
|
|
|
|
- P3 multi-carrier が E2E で動作確認 ✅
|
|
|
|
|
|
- phase195_sum_count.hako → 72 ✅
|
|
|
|
|
|
- 既存テスト(P1/P2/P3/P4)退行なし ✅
|
|
|
|
|
|
|
|
|
|
|
|
**技術的発見**:
|
|
|
|
|
|
- [Root cause: remapper 適用忘れ / block 上書き / 等]
|
|
|
|
|
|
- Select 展開は 1 箇所に集約(joinir_block.rs)
|
|
|
|
|
|
- bridge 層の修正でパターン側に影響なし
|
|
|
|
|
|
|
|
|
|
|
|
**次のステップ**: Phase 197(JsonParser 残り適用)or Phase 200+(ConditionEnv 拡張)
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 3. joinir-architecture-overview.md 更新
|
|
|
|
|
|
|
|
|
|
|
|
Section 7.2 に追記:
|
|
|
|
|
|
|
|
|
|
|
|
```markdown
|
|
|
|
|
|
- [x] **Phase 196**: Select 展開/変換バグ修正
|
|
|
|
|
|
- JoinIR→MIR の Select→Branch+Phi 変換を修正
|
|
|
|
|
|
- PHI inputs に remapper を正しく適用
|
|
|
|
|
|
- P3 multi-carrier が E2E で動作確認完了
|
|
|
|
|
|
- Select 展開は joinir_block.rs::handle_select に集約
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 成功基準
|
|
|
|
|
|
|
|
|
|
|
|
- [x] 最小再現ケース固定(phase196-select-bug-analysis.md)
|
|
|
|
|
|
- [x] Select 展開経路の責務特定(doc に記録)
|
|
|
|
|
|
- [x] 修正実装(1箇所のみ、箱は増やさない)
|
|
|
|
|
|
- [x] phase195_sum_count.hako → 72 ✅
|
|
|
|
|
|
- [x] 既存テスト退行なし(P1/P2/P3/P4)
|
|
|
|
|
|
- [x] ドキュメント更新(Before/After 記録)
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 関連ファイル
|
|
|
|
|
|
|
|
|
|
|
|
### 調査対象
|
|
|
|
|
|
- `src/mir/join_ir_vm_bridge/convert.rs`(読み取り)
|
|
|
|
|
|
- `src/mir/builder/control_flow/joinir/merge/instruction_rewriter.rs`(読み取り)
|
|
|
|
|
|
- `src/mir/join_ir/joinir_block.rs`(**修正対象**)
|
|
|
|
|
|
|
|
|
|
|
|
### テストファイル
|
|
|
|
|
|
- `apps/tests/phase195_sum_count.hako`(最小再現)
|
|
|
|
|
|
- `apps/tests/loop_if_phi.hako`(退行確認)
|
|
|
|
|
|
- `apps/tests/loop_min_while.hako`(P1 退行確認)
|
|
|
|
|
|
- `apps/tests/joinir_min_loop.hako`(P2 退行確認)
|
|
|
|
|
|
- `apps/tests/loop_continue_pattern4.hako`(P4 退行確認)
|
|
|
|
|
|
|
|
|
|
|
|
### ドキュメント
|
|
|
|
|
|
- `docs/development/current/main/phase196-select-bug-analysis.md`(新規作成)
|
|
|
|
|
|
- `docs/development/current/main/joinir-architecture-overview.md`(更新)
|
|
|
|
|
|
- `CURRENT_TASK.md`(Phase 196 完了マーク)
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 設計原則(Phase 196)
|
|
|
|
|
|
|
|
|
|
|
|
1. **最小限の変更**:
|
|
|
|
|
|
- 既存 Select 展開ロジックの中だけを修正
|
|
|
|
|
|
- 新規箱なし(bridge 層の修正のみ)
|
|
|
|
|
|
|
|
|
|
|
|
2. **1箇所に集中**:
|
|
|
|
|
|
- 複数箇所の同時変更は避ける
|
|
|
|
|
|
- 1つの候補に集中して修正 → テスト → 次へ
|
|
|
|
|
|
|
|
|
|
|
|
3. **明示的エラー**:
|
|
|
|
|
|
- remapper.get_value() が None なら明示的に失敗
|
|
|
|
|
|
- 「なんとなく動く」より「壊れたら明示的に失敗」
|
|
|
|
|
|
|
|
|
|
|
|
4. **ドキュメント駆動**:
|
|
|
|
|
|
- Before/After を明確に記録
|
|
|
|
|
|
- 将来同じバグが起きないように教訓を残す
|
2025-12-09 14:56:05 +09:00
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## Implementation Results(完了: 2025-12-09)
|
|
|
|
|
|
|
|
|
|
|
|
**Status**: ✅ Complete
|
|
|
|
|
|
|
|
|
|
|
|
### 修正ポイント
|
|
|
|
|
|
|
|
|
|
|
|
**File**: `src/mir/builder/control_flow/joinir/merge/instruction_rewriter.rs`
|
|
|
|
|
|
**Line**: 317-335
|
|
|
|
|
|
|
|
|
|
|
|
**根本原因**: PHI inputs の ValueId が二重に remap されていた
|
|
|
|
|
|
- Line 304: `remap_instruction()` で JoinIR ValueId → Host ValueId に remap 済み
|
|
|
|
|
|
- Line 328: `remap_value(*val)` で再度 remap を試行 → undefined ValueId 参照
|
|
|
|
|
|
|
|
|
|
|
|
**修正内容**: Block ID のみ remap、ValueId は既に remap 済みなのでそのまま使用
|
|
|
|
|
|
|
|
|
|
|
|
```rust
|
|
|
|
|
|
// Before (Phase 172 - 壊れていた)
|
|
|
|
|
|
let remapped_val = remapper.remap_value(*val); // ❌ 二重 remap
|
|
|
|
|
|
(remapped_bb, remapped_val)
|
|
|
|
|
|
|
|
|
|
|
|
// After (Phase 196 - 修正後)
|
|
|
|
|
|
(remapped_bb, *val) // ✅ 値はそのまま使用(既に remap 済み)
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 具体例
|
|
|
|
|
|
|
|
|
|
|
|
**Before**:
|
|
|
|
|
|
```
|
|
|
|
|
|
bb10:
|
|
|
|
|
|
%27 = phi [%28, bb8], [%32, bb9] // %28, %32 undefined
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
**After**:
|
|
|
|
|
|
```
|
|
|
|
|
|
bb10:
|
|
|
|
|
|
%27 = phi [%21, bb8], [%25, bb9] // %21, %25 correctly defined
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 検証結果
|
|
|
|
|
|
|
|
|
|
|
|
- ✅ **phase195_sum_count.hako**: 93(multi-carrier P3)
|
|
|
|
|
|
- ✅ **loop_if_phi.hako**: sum=9(single-carrier P3)
|
|
|
|
|
|
- ✅ **loop_min_while.hako**: 0,1,2(Pattern 1)
|
|
|
|
|
|
- ✅ **joinir_min_loop.hako**: RC:0(Pattern 2)
|
|
|
|
|
|
- ✅ **退行なし**: 全 Pattern (P1/P2/P3/P4) PASS
|
|
|
|
|
|
- ✅ **`[joinir/freeze]` なし**
|
|
|
|
|
|
|
|
|
|
|
|
### 詳細分析
|
|
|
|
|
|
|
|
|
|
|
|
完全な Before/After 分析、根本原因調査、テスト結果は以下を参照:
|
|
|
|
|
|
- **[phase196-select-bug-analysis.md](./phase196-select-bug-analysis.md)**
|
|
|
|
|
|
|
|
|
|
|
|
### コミット
|
|
|
|
|
|
|
|
|
|
|
|
- **[996925eb]** fix(joinir): Phase 196 Select double-remap bug in instruction_rewriter
|