Files
hakorune/docs/development/roadmap/phases/phase-26-H/README.md
nyash-codex 2692eafbbf 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

8.0 KiB
Raw Blame History

Phase 26-H — JoinIR / 関数正規化フェーズ設計図

目的: これまで「構文 → LoopForm → PHI」で説明してきた制御構造を、もう一段抽象度を上げて「関数呼び出し継続」に正規化する中間層JoinIR / LoopFnIRとして整理し直すこと。
最終的には「ループや if の合流点で悩む」のではなく、「関数の引数と戻り先で意味が決まる」世界に寄せ、箱の数と責務を減らしていく。

このフェーズ 26H ではあくまで「設計とミニ実験」に留め、スモークや本線は既存の MIR/LoopForm ルートのまま維持する。


1. 現状: LoopForm 正規化ベースの世界

現在のパイプライン(概略):

AST  →  MIR / LoopForm v2  →  VM / LLVM

LoopForm v2 / PHI 周辺には、だいたい次のような箱が存在している:

  • 構造系
    • LoopFormBuilder / LoopFormOps
    • ControlFormIf/Loop の形と preds
  • PHI 生成系
    • HeaderPhiBuilder
    • ExitPhiBuilder
    • BodyLocalPhiBuilder
    • IfBodyLocalMergeBox
    • PhiBuilderBoxIf φ 統合)
    • PhiInvariantsBoxFail-Fast チェック)
  • 解析/分類系
    • LoopVarClassBoxPinned / Carrier / BodyLocal*
    • LoopExitLivenessBoxExitLiveness、実装は段階的
    • LocalScopeInspectorBox
    • if 解析系(if_phi.rs の補助群)

これらの箱が「どの変数がループをまたぐか」「どこで φ が必要か」「Exit で何を Live とみなすか」を決めているが、その分、箱の数と責務が多く、ループの形を変えるたびに PHI 側の負担が増えている。


2. 代案: 「関数を呼ぶ回数=ループ」というモデル

発想の転換:

  • 今: 構文を LoopForm に正規化し、ループ構造header/body/latch/exitを中心に世界を説明している。
  • 代案: 構文を「関数呼び出し」に正規化し、関数を繰り返し呼ぶこと自体がループというモデルに寄せる。

2.1 ループの例

元のコード(擬似 Nyash:

var x = 0
loop {
  x = x + 1
  if x >= 10 { break }
}
print(x)

関数ループモデルで見ると:

// ループ一歩ぶんの関数Box
step(x, k_exit) {
  if x >= 10 {
    k_exit(x)             // ループ終了して「先」に進む
  } else {
    step(x + 1, k_exit)   // もう一周
  }
}

// ループの「先」の処理
k_exit = (v) => {
  print(v)
}

// 実行開始
step(0, k_exit)
  • ループ = step を何回も呼ぶこと
  • break = k_exit(...) を呼ぶこと
  • continue = step(...) を呼ぶこと
  • φ / LoopCarried 変数 = step の引数

ここでは「ループヘッダの φ で悩む」のではなく、「step の引数・k_exit の引数をどう定義するか」に責務が集中する。

2.2 パイプラインの再構成案

現在:

AST  →  MIR / LoopForm v2  →  VM/LLVM

ここに 1 段挟む:

AST  →  MIR / LoopForm v2  →  ★LoopFnIR(関数ループ層)  →  VM/LLVM

この LoopFnIR/JoinIR 層で:

  • 各 LoopForm について「ループ関数(step) + 継続関数(k_exit)」を合成。
  • ループの PHI / carrier / exit φ はすべて step / k_exit の引数として表現。
  • 下流VM / LLVMは「関数呼び出しおよび再帰のループ化や展開」だけを見ればよい。

結果として:

  • LoopForm v2 は「LoopFnIR を作る前段」に役割縮小。
  • BodyLocal / Exit φ の詳細設計は「引数に何を持っていくか?」という関数インターフェース設計に吸収される。

4. このフェーズで実装する箱 / 概念ラベル

  • 実装として増やす26-H 内で手を動かすもの)

    • join_ir.rs: JoinIR 型(関数/ブロック/命令)+ダンプ
    • LoopForm→JoinIR のミニ変換1 ケース限定で OK
    • 実験トグル(例: NYASH_JOINIR_EXPERIMENT=1)で JoinIR をダンプするフック
  • 概念ラベル27.x 以降に検討)

    • MirQuery のようなビュー層reads/writes/succs を trait 化)
    • LoopFnLoweringBox / JoinIRBox の分割や最適化パス
    • VM/LLVM への統合

※ このフェーズでは「設計+ミニ実験のみ」で、本線スモークは既存 MIR/LoopForm 経路を維持する。


3. 箱の数と最終形のイメージ

3.1 現在の PHI/Loop 周辺の箱(概略)

ざっくりカテゴリ分けすると:

  • 構造:
    • LoopFormBuilder
    • ControlForm
  • PHI 生成:
    • HeaderPhiBuilder
    • ExitPhiBuilder
    • BodyLocalPhiBuilder
    • IfBodyLocalMergeBox
    • PhiBuilderBox
    • PhiInvariantsBox
  • 解析:
    • LoopVarClassBox
    • LoopExitLivenessBox
    • LocalScopeInspectorBox
    • if 解析系IfAnalysisBox 的なもの)

関数正規化前提で進むと、最終的には:

  • PHI を直接扱う箱は「LoopForm→LoopFnIR に変換する前段」に閉じ込める。
  • LoopFnIR 導入後の本線では、次のような少数の箱が中心になる:
    • LoopFnLoweringBoxLoopForm → LoopFnIR / JoinIR
    • JoinIRBoxJoinIR の保持・最適化)
    • 既存の VM/LLVM バックエンドJoinIR からのコード生成側)

という構造に寄せられる見込み。

このフェーズ 26H では、「最終的にそこに寄せるための設計図」を書くところまでを目標とする。


4. 26-H でやること(スコープ)

  • JoinIR / LoopFnIR の設計ドキュメント作成
    • 命令セットcall / ret / jump / 継続)の最小定義。
    • if / loop / break / continue / return を JoinIR に落とす書き換え規則。
    • φ = 関数引数、merge = join 関数、loop = 再帰関数exit 継続、という対応表。
  • 最小 1 ケースの手書き変換実験MIR → JoinIR
    • ループbreak を含む簡単な関数を 1 例だけ JoinIR に落とし、形を確認。
  • MirQueryBox 経由で必要な MIR ビュー API の確認
    • reads/writes/succs など、JoinIR 変換に必要な情報がすでに MirQuery で取れるかチェック。
  • すべてトグル OFF で行い、本線MIR/LoopForm ルート)のスモークには影響させない。

5. やらないこと26-H では保留)

  • 既存ルートMIR/LoopForm/VM/LLVMを JoinIR で置き換える。
  • スモーク / CI のデフォルト経路変更。
  • Loop/PHI 既存実装の削除(これは 27.x 以降の段階で検討)。

6. 実験計画(段階)

  1. 設計シート

    • docs/development/architecture/join-ir.md に命令セット・変換規則・対応表を記述(φ=引数, merge=join, loop=再帰)。
  2. ミニ変換実験 1 ケース

    • 最小ループ(例: loop(i < 3) { if i >= 2 { break } i = i + 1 } return i)を MIR → JoinIR へ手書き変換し、テストでダンプを確認。VM/LLVM 実行までは行わない。
  3. トランスレータ骨格

    • src/mir/join_ir.rs などに型定義だけ追加(未配線、トグル OFF。MirQueryBoxreads/writes/succsで必要なビューが揃っているか確認。
  4. トグル付き実験

    • NYASH_JOINIR_EXPERIMENT=1 などのトグルで最小ケースを JoinIR 変換・ダンプするルートを作る(デフォルト OFF でスモーク影響なし)。

7. 受け入れ基準(このフェーズ)

  • docs に JoinIR / LoopFnIR の設計と変換規則が明記されている。
  • 最小 1 ケースの JoinIR 変換がテストでダンプできるjoin/step/k_exit の形になっている)。
  • 本線スモーク(既存 MIR ルート)は影響なし(トグル OFF

8. 次フェーズへの橋渡し

  • 変換器を拡張して FuncScanner / StageB などカナリアを JoinIR で通す(トグル付き)。
  • ExitLiveness や BodyLocal PHI の一部を LoopFnIR 側に吸収し、PHI/Loop 周辺の箱を徐々に減らす。
  • VM/LLVM 実行経路に JoinIR を統合するのは 27.x 以降を想定し、当面は「設計+ミニ実験」に留める。