Files
hakorune/docs/development/architecture/loops/loopform_ssot.md

100 lines
6.6 KiB
Markdown
Raw Normal View History

# LoopForm SSOT単一起点設計ート
目的
- ループのPHI整形・前処理preheader Copy、header PHI seed、latch/continue 合流)を単一モジュールに集約してドリフトを防ぐ。
- ビルダーDirect MIRとブリッジJSON v0 → MIRの双方で同一の規約と検証を通す。
SSOTSingle Source of Truth
- 中心: `src/mir/phi_core/loop_phi.rs`
- 型: `IncompletePhi`, `VarSnapshot`
- API: `prepare_loop_variables_with`, `seal_incomplete_phis_with`, `build_exit_phis_with`
- デバッグ: `phi_core::common::debug_verify_phi_inputs`(到達検証・重複検出)
- Direct MIR既にSSOT使用
- `src/mir/loop_builder.rs``LoopPhiOps` を実装し、`prepare/seal/exit` を phi_core へ委譲。
- 形状: `preheader → header(φ) → body → latch → header|exit`LoopForm準拠
- JSON v0 Bridge段階移行→完了済みの範囲
- header PHIseed/完成・exit PHI を `LoopPhiOps` アダプタ経由で SSOT API に委譲。
- break/continue スナップショットは threadlocal stack で収集し、seal/build_exit に渡す。
- 代表 parity カナリアoptinで Direct と Bridge の一致を検証。
規約(不変条件)
- header の PHI 入力は「preheader 経由の定義済み値」と「latch/continue からの値」だけ。
- preheader で Copy を先行挿入し、PHI 入力は Copy の出力を参照するUse-Before-Def回避
- 1 predecessor なら直接 bindPHI省略、2つ以上で PHI を生成。
- 検証は FailFast ではなく開発時 WARN`debug_assert`)だが、将来 Core 側で整形に移管予定。
feat(mir): Phase 26-H JoinIR型定義実装完了 - ChatGPT設計 ## 実装内容(Step 1-3 完全達成) ### Step 1: src/mir/join_ir.rs 型定義追加 - **JoinFuncId / JoinContId**: 関数・継続ID型 - **JoinFunction**: 関数(引数 = φノード) - **JoinInst**: Call/Jump/Ret/Compute 最小命令セット - **MirLikeInst**: 算術・比較命令ラッパー - **JoinModule**: 複数関数保持コンテナ - **単体テスト**: 型サニティチェック追加 ### Step 2: テストケース追加 - **apps/tests/joinir_min_loop.hako**: 最小ループ+breakカナリア - **src/tests/mir_joinir_min.rs**: 手書きJoinIR構築テスト - MIR → JoinIR手動構築で型妥当性確認 - #[ignore] で手動実行専用化 - NYASH_JOINIR_EXPERIMENT=1 トグル制御 ### Step 3: 環境変数トグル実装 - **NYASH_JOINIR_EXPERIMENT=1**: 実験モード有効化 - **デフォルト挙動**: 既存MIR/LoopForm経路のみ(破壊的変更なし) - **トグルON時**: JoinIR手書き構築テスト実行 ## Phase 26-H スコープ遵守 ✅ 型定義のみ(変換ロジックは未実装) ✅ 最小限の命令セット ✅ Debug 出力で妥当性確認 ✅ 既存パイプライン無影響 ## テスト結果 ``` $ NYASH_JOINIR_EXPERIMENT=1 cargo test --release mir_joinir_min_manual_construction -- --ignored --nocapture [joinir/min] MIR module compiled, 3 functions [joinir/min] JoinIR module constructed: [joinir/min] ✅ JoinIR型定義は妥当(Phase 26-H) test result: ok. 1 passed; 0 failed ``` ## JoinIR理論の実証 - **φノード = 関数引数**: `fn loop_step(i, k_exit)` - **merge = join関数**: 分岐後の合流点 - **ループ = 再帰関数**: `loop_step` 自己呼び出し - **break = 継続呼び出し**: `k_exit(i)` ## 次フェーズ (Phase 27.x) - LoopForm v2 → JoinIR 自動変換実装 - break/continue ハンドリング - Exit PHI の JoinIR 引数化 🌟 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> Co-Authored-By: ChatGPT <noreply@openai.com>
2025-11-23 04:10:12 +09:00
4箱構成Phase 26-F 系の整理)
- **LoopVarClassBox**`loop_var_classifier.rs`
- 変数のスコープ分類専用箱だよ。Pinned / Carrier / BodyLocalExit / BodyLocalInternal を決めるだけで、PHI 発行はしない。
- **LoopExitLivenessBox**`loop_exit_liveness.rs`
- ループ `exit` 直後で「実際に使われる可能性がある変数」を集める箱だよ。Phase 26-F 時点では `live_at_exit` は保守的近似で、将来 `get_block_instructions()` などを使った MIR スキャンに差し替える予定。
- `ExitLivenessProvider` を実装していて、`ExitPhiBuilder` は Box<dyn ExitLivenessProvider> を受け取る形にしたので、Legacy既定と MirScan 版の差し替えがそのまま出来る。
- 環境変数 `NYASH_EXIT_LIVE_ENABLE=1` で将来の実装を段階的に有効化、`NYASH_EXIT_LIVENESS_TRACE=1` でトレースを出せるようにしてある。
- **BodyLocalPhiBuilder**`body_local_phi_builder.rs`
- 上の 2つの箱の結果を統合する決定箱だよ。
- `class.needs_exit_phi()` が truePinned / Carrier / BodyLocalExitのものは従来どおり exit PHI 候補。
- それ以外でも、`BodyLocalInternal` かつ `live_at_exit` に含まれ、かつ `is_available_in_all` で全 pred 定義が確認できるものだけを安全側で救済候補にできるようにしてある(この救済ロジック自体は `NYASH_EXIT_LIVE_ENABLE` でガード)。
- **PhiInvariantsBox**`phi_invariants.rs`
- 最後に「全 pred で定義されているか」「不正な incoming が無いか」を Fail-Fast でチェックする箱だよ。ここで落ちる場合は LoopForm/BodyLocal 側の構造バグとみなしている。
今後の移行
- Bridge 側に `LoopPhiOps` 実装を追加し、`prepare/seal/exit` を直接呼ぶ。
- ループ形状の生成をユーティリティ化builder/bridge 双方から共通呼び出し)。
feat(mir): Phase 26-H JoinIR型定義実装完了 - ChatGPT設計 ## 実装内容(Step 1-3 完全達成) ### Step 1: src/mir/join_ir.rs 型定義追加 - **JoinFuncId / JoinContId**: 関数・継続ID型 - **JoinFunction**: 関数(引数 = φノード) - **JoinInst**: Call/Jump/Ret/Compute 最小命令セット - **MirLikeInst**: 算術・比較命令ラッパー - **JoinModule**: 複数関数保持コンテナ - **単体テスト**: 型サニティチェック追加 ### Step 2: テストケース追加 - **apps/tests/joinir_min_loop.hako**: 最小ループ+breakカナリア - **src/tests/mir_joinir_min.rs**: 手書きJoinIR構築テスト - MIR → JoinIR手動構築で型妥当性確認 - #[ignore] で手動実行専用化 - NYASH_JOINIR_EXPERIMENT=1 トグル制御 ### Step 3: 環境変数トグル実装 - **NYASH_JOINIR_EXPERIMENT=1**: 実験モード有効化 - **デフォルト挙動**: 既存MIR/LoopForm経路のみ(破壊的変更なし) - **トグルON時**: JoinIR手書き構築テスト実行 ## Phase 26-H スコープ遵守 ✅ 型定義のみ(変換ロジックは未実装) ✅ 最小限の命令セット ✅ Debug 出力で妥当性確認 ✅ 既存パイプライン無影響 ## テスト結果 ``` $ NYASH_JOINIR_EXPERIMENT=1 cargo test --release mir_joinir_min_manual_construction -- --ignored --nocapture [joinir/min] MIR module compiled, 3 functions [joinir/min] JoinIR module constructed: [joinir/min] ✅ JoinIR型定義は妥当(Phase 26-H) test result: ok. 1 passed; 0 failed ``` ## JoinIR理論の実証 - **φノード = 関数引数**: `fn loop_step(i, k_exit)` - **merge = join関数**: 分岐後の合流点 - **ループ = 再帰関数**: `loop_step` 自己呼び出し - **break = 継続呼び出し**: `k_exit(i)` ## 次フェーズ (Phase 27.x) - LoopForm v2 → JoinIR 自動変換実装 - break/continue ハンドリング - Exit PHI の JoinIR 引数化 🌟 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> Co-Authored-By: ChatGPT <noreply@openai.com>
2025-11-23 04:10:12 +09:00
- ExitLivenessProvider は 26-G 以降で MIR 命令列スキャン版に差し替える予定(現状の MirScanExitLiveness は header/exit_snapshots の union 近似)。
---
## LoopForm v2 ケース表
| Case | loop 条件形 | exit preds の構成 | 想定される PHI 入力の形 | 対応テスト | 対応 .hako |
|------|-----------|-----------------|---------------------|----------|-----------|
| **A** | `loop(i < n)` | header / body | header fallthrough + break | `loop_conditional_reassign_exit_phi_header_and_break` | - |
| **B** | `loop(1 == 1)` | body のみ | break のみ | `loop_constant_true_exit_phi_dominates` | `apps/tests/minimal_ssa_skip_ws.hako` |
| **C** | `loop(1 == 1)` + body-local | body のみ(一部の経路のみ定義) | break のみBodyLocalInternal は除外) | `loop_body_local_exit_phi_body_only` | - |
| **D** | `loop(i < n)` + continue | header / body / continue_merge | header + break + continue_merge | `loop_continue_merge_header_exit` | - |
### ケース説明
#### Case A: header+break標準パターン
- **条件**: `loop(i < n)` のような動的条件
- **特徴**: header→exit と body→exit の両方が CFG 上存在
- **exit PHI**: header fallthrough + break 経路の両方を含む
- **検証**: `loop_conditional_reassign_exit_phi_header_and_break`
#### Case B: constant-true+break-onlyheader 除外パターン)
- **条件**: `loop(1 == 1)` のような定数 true
- **特徴**: exit pred は break 経路のみ(`header→exit` は無い)
- **exit PHI**: break 経路のみheader は CFG predecessor でないため除外)
- **検証**: `loop_constant_true_exit_phi_dominates` + `minimal_ssa_skip_ws.hako`
#### Case C: body-local変数BodyLocalInternal 除外パターン)
- **条件**: body 内で宣言された変数が一部の exit 経路でのみ定義される
- **特徴**: 変数が全 exit predecessors で定義されていない
- **exit PHI**: BodyLocalInternal 変数は除外PHI 生成しない)
- **検証**: `loop_body_local_exit_phi_body_only`
#### Case D: continue+breakcontinue_merge パターン)
- **条件**: continue 文を含むループ
- **特徴**: `continue_merge → header → exit` の経路あり
- **exit PHI**: header + break + continue_merge の 3 系統
- **検証**: `loop_continue_merge_header_exit`
### 実装ファイル
| ファイル | 役割 |
|---------|-----|
| `src/mir/loop_builder.rs` | ループ構造生成・[LoopForm] コメント付き |
| `src/mir/phi_core/loop_snapshot_merge.rs` | Case A/B 分岐ロジック |
| `src/mir/phi_core/exit_phi_builder.rs` | Exit PHI 生成・Phantom block 除外 |
| `src/tests/mir_loopform_conditional_reassign.rs` | 4 ケース全てのテスト([LoopForm-Test] タグ付き) |
---
関連
- `src/mir/loop_builder.rs`
- `src/runner/json_v0_bridge/lowering/loop_.rs`
- `src/mir/phi_core/common.rs`
- `src/mir/phi_core/loop_snapshot_merge.rs`
- `src/mir/phi_core/exit_phi_builder.rs`
- `src/tests/mir_loopform_conditional_reassign.rs`