125 lines
3.4 KiB
Markdown
125 lines
3.4 KiB
Markdown
|
|
# Phase 116: if-only keep+call merge parity
|
|||
|
|
|
|||
|
|
**Status**: ✅ DONE
|
|||
|
|
**Date**: 2025-12-18
|
|||
|
|
|
|||
|
|
## 背景
|
|||
|
|
|
|||
|
|
LLVMバックエンドで壊れやすいパターンの固定: 片側が元値保持、片側がcall結果のmerge。
|
|||
|
|
|
|||
|
|
### 問題のパターン
|
|||
|
|
|
|||
|
|
```hako
|
|||
|
|
fn f(x) { return x + 1 }
|
|||
|
|
fn g(flag) {
|
|||
|
|
local v = 10
|
|||
|
|
if flag == 1 { v = f(1) }
|
|||
|
|
// else側は暗黙的にv=10を保持
|
|||
|
|
print(v)
|
|||
|
|
}
|
|||
|
|
g(0) // → 10 (元値保持)
|
|||
|
|
g(1) // → 2 (f(1) = 1+1 = 2)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
- **then側**: call結果でvを更新 (`v = f(1)`)
|
|||
|
|
- **else側**: 元の値を保持 (`v = 10`)
|
|||
|
|
- **merge地点**: 2つの異なるソース(元値 vs call結果)からのPHI
|
|||
|
|
|
|||
|
|
## 実装内容
|
|||
|
|
|
|||
|
|
### 1. テストフィクスチャ
|
|||
|
|
|
|||
|
|
**ファイル**: `apps/tests/phase116_if_only_keep_plus_call_min.hako`
|
|||
|
|
|
|||
|
|
最小限のケース:
|
|||
|
|
- `g(0)` → `10` (元値保持)
|
|||
|
|
- `g(1)` → `2` (call結果)
|
|||
|
|
|
|||
|
|
### 2. VM smoke test
|
|||
|
|
|
|||
|
|
**ファイル**: `tools/smokes/v2/profiles/integration/apps/phase116_if_only_keep_plus_call_vm.sh`
|
|||
|
|
|
|||
|
|
- `output_validator.sh` を使用して数値2行 `10\n2` を検証
|
|||
|
|
- 実行条件: `NYASH_DISABLE_PLUGINS=1 HAKO_JOINIR_STRICT=1`
|
|||
|
|
|
|||
|
|
### 3. LLVM EXE smoke test
|
|||
|
|
|
|||
|
|
**ファイル**: `tools/smokes/v2/profiles/integration/apps/phase116_if_only_keep_plus_call_llvm_exe.sh`
|
|||
|
|
|
|||
|
|
- `llvm_exe_runner.sh` を利用(plugin dlopen/cache/build-all SSOT)
|
|||
|
|
- `llvm_exe_build_and_run_numeric_smoke` で出力検証(`10\n2`)
|
|||
|
|
|
|||
|
|
## 検証コマンド
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
# VM smoke test
|
|||
|
|
bash tools/smokes/v2/profiles/integration/apps/phase116_if_only_keep_plus_call_vm.sh
|
|||
|
|
|
|||
|
|
# LLVM EXE smoke test
|
|||
|
|
bash tools/smokes/v2/profiles/integration/apps/phase116_if_only_keep_plus_call_llvm_exe.sh
|
|||
|
|
|
|||
|
|
# 回帰テスト (Phase 115)
|
|||
|
|
bash tools/smokes/v2/profiles/integration/apps/phase115_if_only_call_merge_llvm_exe.sh
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 技術的詳細
|
|||
|
|
|
|||
|
|
### JoinIR Pattern
|
|||
|
|
|
|||
|
|
このケースは **Pattern 1 (Simple If)** として処理される:
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
entry_block:
|
|||
|
|
v = 10
|
|||
|
|
if flag == 1 goto then_block else exit_block
|
|||
|
|
|
|||
|
|
then_block:
|
|||
|
|
v = f(1)
|
|||
|
|
goto exit_block
|
|||
|
|
|
|||
|
|
exit_block:
|
|||
|
|
v_merged = PHI [v=10 from entry, v=f(1) from then]
|
|||
|
|
print(v_merged)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### PHI接続の重要性
|
|||
|
|
|
|||
|
|
- **entry → exit**: 元値 (`10`) を直接伝播
|
|||
|
|
- **then → exit**: call結果 (`f(1)`) を伝播
|
|||
|
|
- **PHI**: 2つの異なる型のソース(変数 vs call結果)を正しくmerge
|
|||
|
|
|
|||
|
|
LLVM IRでは、これらが適切な型で統一される必要がある。
|
|||
|
|
|
|||
|
|
## 期待される効果
|
|||
|
|
|
|||
|
|
1. **LLVM安定性向上**: keep+call mergeパターンの回帰を防止
|
|||
|
|
2. **PHI生成品質**: 異なるソースタイプのmerge処理の検証
|
|||
|
|
3. **パリティ保証**: VM/LLVM両方で同じ動作を保証
|
|||
|
|
|
|||
|
|
## 関連Phase
|
|||
|
|
|
|||
|
|
- **Phase 115**: if-only call result merge (両側がcall)
|
|||
|
|
- **Phase 114**: if-only PHI minimal (基本的なPHI)
|
|||
|
|
- **Phase 33**: Box Theory Modularization (JoinIR architecture)
|
|||
|
|
|
|||
|
|
## Lessons Learned
|
|||
|
|
|
|||
|
|
### Box-First原則の適用
|
|||
|
|
|
|||
|
|
このPhaseでは、既存の箱化されたコンポーネントを活用:
|
|||
|
|
|
|||
|
|
- ✅ `output_validator.sh` による出力検証の統一
|
|||
|
|
- ✅ `llvm_exe_runner.sh` によるLLVM実行の標準化
|
|||
|
|
- ✅ テストインフラの再利用(no reinvention)
|
|||
|
|
|
|||
|
|
### Fail-Fast原則
|
|||
|
|
|
|||
|
|
- VM/LLVM両方でエラーを即座に検出
|
|||
|
|
- `HAKO_JOINIR_STRICT=1` で厳密な検証を有効化
|
|||
|
|
- フォールバック処理なし(エラーは明示的に失敗)
|
|||
|
|
|
|||
|
|
## Future Work
|
|||
|
|
|
|||
|
|
- **Phase 117+**: より複雑なmergeパターン(両側keep、ネストしたcall等)
|
|||
|
|
- **最適化**: 元値保持の場合のPHI削減の可能性検討
|