2025-12-07 21:02:20 +09:00
|
|
|
|
# JoinIR Architecture Overview (2025‑12‑06)
|
|
|
|
|
|
|
|
|
|
|
|
このドキュメントは、JoinIR ライン全体(Loop/If lowering, ExitLine, Boundary, 条件式 lowering)の
|
|
|
|
|
|
「箱」と「契約」を横串でまとめた設計図だよ。selfhost / JsonParser / hako_check など、
|
|
|
|
|
|
どの呼び出し元から見てもここを見れば「JoinIR 層の責務と流れ」が分かるようにしておく。
|
|
|
|
|
|
|
|
|
|
|
|
変更があったら、Phase ドキュメントではなく **このファイルを随時更新する** 方針。
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 1. 不変条件(Invariants)
|
|
|
|
|
|
|
|
|
|
|
|
JoinIR ラインで守るべきルールを先に書いておくよ:
|
|
|
|
|
|
|
|
|
|
|
|
1. **JoinIR 内部は JoinIR ValueId だけ**
|
|
|
|
|
|
- JoinIR lowering が発行する `JoinInst` の `ValueId` は、すべて `alloc_value()` で割り当てるローカル ID。
|
|
|
|
|
|
- Rust/MIR 側の ValueId(`builder.variable_map` に入っている ID)は、JoinIR には直接持ち込まない。
|
|
|
|
|
|
|
|
|
|
|
|
2. **host ↔ join の橋渡しは JoinInlineBoundary 系だけ**
|
|
|
|
|
|
- host から JoinIR への入力(ループ変数 / 条件専用変数)は
|
|
|
|
|
|
- `JoinInlineBoundary.join_inputs + host_inputs`
|
|
|
|
|
|
- `JoinInlineBoundary.condition_bindings`(ConditionBinding)
|
|
|
|
|
|
だけで接続する。
|
|
|
|
|
|
- 出力(キャリアの出口)は `JoinInlineBoundary.exit_bindings` に一本化する。
|
|
|
|
|
|
|
|
|
|
|
|
3. **式としての戻り値とキャリア更新を分離する**
|
|
|
|
|
|
- 「ループが式として値を返す」ケース(例: `let r = loop_min_while(...)`)の出口は **exit_phi_builder** が扱う。
|
|
|
|
|
|
- 「ループが状態更新だけする」ケース(例: `trim` の `start/end`)の出口は **ExitLine(ExitMeta / ExitBinding / ExitLineReconnector)** だけが扱う。
|
|
|
|
|
|
|
|
|
|
|
|
4. **ループ制御 vs 条件式の分離**
|
|
|
|
|
|
- ループの「形」(Pattern1–4, LoopFeatures)は control-flow 専用の箱が担当。
|
|
|
|
|
|
- 条件式(`i < len && (ch == " " || ch == "\t")` 等)は **BoolExprLowerer / condition_to_joinir** が担当し、
|
|
|
|
|
|
ループパターンは boolean ValueId だけを受け取る。
|
|
|
|
|
|
|
|
|
|
|
|
5. **Fail‑Fast**
|
|
|
|
|
|
- JoinIR が対応していないループパターン / if パターンは、必ず `[joinir/freeze]` 等で明示的にエラーにする。
|
|
|
|
|
|
- LoopBuilder 等へのサイレントフォールバックは禁止(Phase 186–187 で完全削除済み)。
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 2. 主な箱と責務
|
|
|
|
|
|
|
|
|
|
|
|
### 2.1 Loop 構造・検出ライン
|
|
|
|
|
|
|
|
|
|
|
|
- **LoopFeatures / LoopPatternKind / router**
|
|
|
|
|
|
- ファイル:
|
|
|
|
|
|
- `src/mir/loop_pattern_detection.rs`
|
|
|
|
|
|
- `src/mir/builder/control_flow/joinir/patterns/router.rs`
|
|
|
|
|
|
- 責務:
|
|
|
|
|
|
- AST からループ構造の特徴(`has_break`, `has_continue`, `has_if_else_phi`, `carrier_count` 等)を抽出。
|
|
|
|
|
|
- `classify(&LoopFeatures)` で Pattern1–4 に分類。
|
|
|
|
|
|
- `LOOP_PATTERNS` テーブルを通じて該当 lowerer(pattern*_minimal.rs)にルーティング。
|
|
|
|
|
|
- Phase 170‑C 系で `LoopUpdateSummary`(各キャリアの UpdateKind 情報)を統合し、
|
|
|
|
|
|
`CaseALoweringShape` が関数名ではなく構造+更新パターンだけを見て判定できるようにする計画。
|
|
|
|
|
|
|
|
|
|
|
|
- **Pattern Lowerers (Pattern1–4)**
|
|
|
|
|
|
- ファイル例:
|
|
|
|
|
|
- `simple_while_minimal.rs`(Pattern1)
|
|
|
|
|
|
- `loop_with_break_minimal.rs`(Pattern2)
|
|
|
|
|
|
- `loop_with_if_phi_minimal.rs`(Pattern3)
|
|
|
|
|
|
- `loop_with_continue_minimal.rs`(Pattern4)
|
|
|
|
|
|
- 責務:
|
|
|
|
|
|
- LoopScopeShape / AST / LoopFeatures を入力として JoinIR の `JoinModule` を構築。
|
|
|
|
|
|
- `JoinFragmentMeta{ expr_result, exit_meta }` を返し、出口情報を ExitLine に渡す。
|
|
|
|
|
|
- host/MIR の ValueId は一切扱わない(JoinIR ローカルの ValueId のみ)。
|
|
|
|
|
|
|
|
|
|
|
|
- **CommonPatternInitializer** (Phase 33-22)
|
|
|
|
|
|
- ファイル: `src/mir/builder/control_flow/joinir/patterns/common_init.rs`
|
|
|
|
|
|
- 責務:
|
|
|
|
|
|
- 全 Pattern 共通の初期化ロジック統一化(ループ変数抽出 + CarrierInfo 構築)。
|
|
|
|
|
|
- All 4 loop patterns use this for unified initialization, guaranteeing boundary.loop_var_name is always set and preventing SSA-undef bugs.
|
|
|
|
|
|
|
|
|
|
|
|
- **JoinIRConversionPipeline** (Phase 33-22)
|
|
|
|
|
|
- ファイル: `src/mir/builder/control_flow/joinir/patterns/conversion_pipeline.rs`
|
|
|
|
|
|
- 責務:
|
|
|
|
|
|
- JoinIR → MIR 変換フロー統一化(JoinModule → MirModule → merge_joinir_mir_blocks)。
|
|
|
|
|
|
- Single entry point for JoinIR→MIR conversion, encapsulating phases 1-6 and ensuring consistent transformation across all patterns.
|
|
|
|
|
|
|
|
|
|
|
|
### 2.2 条件式ライン(式の箱)
|
|
|
|
|
|
|
|
|
|
|
|
- **BoolExprLowerer**
|
|
|
|
|
|
- ファイル: `src/mir/join_ir/lowering/bool_expr_lowerer.rs`
|
|
|
|
|
|
- 責務:
|
|
|
|
|
|
- AST の boolean 式 → MIR の Compare/BinOp/UnaryOp に lowering(通常の if/while 用)。
|
|
|
|
|
|
- `<, ==, !=, <=, >=, >` と `&&, ||, !` の組合せを扱う。
|
|
|
|
|
|
|
|
|
|
|
|
- **condition_to_joinir + ConditionEnv/ConditionBinding**
|
|
|
|
|
|
- ファイル: `src/mir/join_ir/lowering/condition_to_joinir.rs`
|
|
|
|
|
|
- 責務:
|
|
|
|
|
|
- ループ lowerer 用の「AST 条件 → JoinIR Compute命令列」。
|
|
|
|
|
|
- `ConditionEnv` 経由で「変数名 → JoinIR ValueId」のみを見る。
|
|
|
|
|
|
- host 側の ValueId は `ConditionBinding { name, host_value, join_value }` として JoinInlineBoundary に記録する。
|
|
|
|
|
|
|
2025-12-07 23:09:25 +09:00
|
|
|
|
- **LoopConditionScopeBox(Phase 170-D 実装済み)**
|
|
|
|
|
|
- ファイル: `src/mir/loop_pattern_detection/loop_condition_scope.rs`
|
2025-12-07 21:29:19 +09:00
|
|
|
|
- 責務:
|
|
|
|
|
|
- 条件式に登場する変数が、ループパラメータ(LoopParam)/ループ外ローカル(OuterLocal)/ループ本体ローカル(LoopBodyLocal)のどれかを分類する。
|
|
|
|
|
|
- Pattern2/4 が「対応してよい条件のスコープ」を判定するための箱。
|
2025-12-07 23:09:25 +09:00
|
|
|
|
- ループ本体ローカルを条件に含む高度なパターンは、**LoopBodyCarrierPromoter(Phase 171)** で carrier に昇格させる。
|
|
|
|
|
|
- **Bug Fix(2025-12-07)**:
|
|
|
|
|
|
- 関数パラメータが LoopBodyLocal と誤分類される問題を修正。
|
|
|
|
|
|
- `condition_var_analyzer.rs` の `is_outer_scope_variable()` で、`variable_definitions` に含まれない変数を OuterLocal とする。
|
|
|
|
|
|
- これにより JsonParserBox などの関数パラメータを含むループが正しく動作。
|
|
|
|
|
|
|
|
|
|
|
|
- **LoopBodyCarrierPromoter(Phase 171-C-1 実装中)**
|
|
|
|
|
|
- ファイル: `src/mir/loop_pattern_detection/loop_body_carrier_promoter.rs`
|
|
|
|
|
|
- 責務:
|
|
|
|
|
|
- LoopBodyLocal 変数を carrier に昇格させ、Pattern 2/4 で処理可能にする。
|
|
|
|
|
|
- 昇格成功 → Pattern 2/4 にルーティング(新しい carrier 情報付き)。
|
|
|
|
|
|
- 昇格失敗 → UnsupportedPattern(Fail-Fast)。
|
|
|
|
|
|
- **Pattern 2/4 + Pattern 5 の境界線**:
|
|
|
|
|
|
- **Pattern 2/4 の守備範囲**: LoopParam + OuterLocal のみ。LoopBodyLocal 条件は受け入れない。
|
|
|
|
|
|
- **Pattern 5 の守備範囲**: LoopBodyLocal を carrier に昇格。成功なら Pattern 2/4 へ委譲。
|
|
|
|
|
|
- **境界**: LoopConditionScopeBox が LoopBodyLocal 検出 → LoopBodyCarrierPromoter で昇格試行。
|
|
|
|
|
|
- **Design Strategy(Design D: Evaluated Bool Carrier)**:
|
|
|
|
|
|
- `ch == " " || ...` のような条件を `is_whitespace` (bool carrier) に変換。
|
|
|
|
|
|
- 昇格例:
|
|
|
|
|
|
```hako
|
|
|
|
|
|
// Before (blocked)
|
|
|
|
|
|
loop(start < end) {
|
|
|
|
|
|
local ch = s.substring(start, start+1)
|
|
|
|
|
|
if ch == " " || ... { ... } else { break }
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// After (Pattern2 compatible)
|
|
|
|
|
|
local is_whitespace = true
|
|
|
|
|
|
loop(start < end && is_whitespace) {
|
|
|
|
|
|
local ch = s.substring(start, start+1)
|
|
|
|
|
|
is_whitespace = (ch == " " || ...)
|
|
|
|
|
|
if is_whitespace { ... } else { break }
|
|
|
|
|
|
}
|
|
|
|
|
|
```
|
|
|
|
|
|
- **Current Status(Phase 171-C-1)**:
|
|
|
|
|
|
- ✅ API 定義: `PromotionRequest` → `PromotionResult`
|
|
|
|
|
|
- ✅ Skeleton 実装: LoopBodyLocal 検出・定義探索
|
|
|
|
|
|
- ⏳ Promotion logic: Phase 171-C-2 で Trim パターンの実際の昇格ロジックを実装予定
|
|
|
|
|
|
- **詳細**: `docs/development/current/main/phase171-pattern5-loop-inventory.md`
|
2025-12-07 21:29:19 +09:00
|
|
|
|
|
2025-12-07 21:02:20 +09:00
|
|
|
|
### 2.3 キャリア / Exit / Boundary ライン
|
|
|
|
|
|
|
|
|
|
|
|
- **CarrierInfo / LoopUpdateAnalyzer**
|
|
|
|
|
|
- ファイル:
|
|
|
|
|
|
- `src/mir/join_ir/lowering/carrier_info.rs`
|
|
|
|
|
|
- `LoopUpdateAnalyzer` 周辺
|
|
|
|
|
|
- 責務:
|
|
|
|
|
|
- ループ内で更新される変数(carrier)の名前と host ValueId を検出。
|
|
|
|
|
|
- 更新式(`sum = sum + i`, `count = count + 1` 等)を `UpdateExpr` として保持。
|
|
|
|
|
|
|
|
|
|
|
|
- **ExitMeta / JoinFragmentMeta**
|
|
|
|
|
|
- ファイル: `carrier_info.rs` 等
|
|
|
|
|
|
- 責務:
|
|
|
|
|
|
- JoinIR lowerer が「どの carrier が、どの JoinIR ValueId で出口に出るか」を記録。
|
|
|
|
|
|
- `JoinFragmentMeta` の一部として `expr_result: Option<ValueId>` と `exit_meta` をまとめる。
|
|
|
|
|
|
|
|
|
|
|
|
- **ExitMetaCollector**
|
|
|
|
|
|
- ファイル: `src/mir/builder/control_flow/joinir/merge/exit_line/meta_collector.rs`
|
|
|
|
|
|
- 責務:
|
|
|
|
|
|
- `ExitMeta + CarrierInfo` から `Vec<LoopExitBinding{ carrier_name, join_exit_value, host_slot }>` を構築。
|
|
|
|
|
|
- 副作用なしの pure function。
|
|
|
|
|
|
|
|
|
|
|
|
- **JoinInlineBoundary**
|
|
|
|
|
|
- ファイル: `src/mir/join_ir/lowering/inline_boundary.rs`
|
|
|
|
|
|
- フィールド(主なもの):
|
|
|
|
|
|
- `join_inputs / host_inputs`:ループパラメータの橋渡し
|
|
|
|
|
|
- `condition_bindings: Vec<ConditionBinding>`:条件専用変数の橋渡し
|
|
|
|
|
|
- `exit_bindings: Vec<LoopExitBinding>`:キャリア出口の橋渡し
|
|
|
|
|
|
- 責務:
|
|
|
|
|
|
- 「host 関数 ↔ JoinIR fragment」の境界情報の SSOT。
|
|
|
|
|
|
|
|
|
|
|
|
- **BoundaryInjector**
|
|
|
|
|
|
- ファイル: `src/mir/builder/joinir_inline_boundary_injector.rs`
|
|
|
|
|
|
- 責務:
|
|
|
|
|
|
- `join_inputs + host_inputs` / `condition_bindings` に基づき、entry block に Copy 命令を挿して host→JoinIR を接続。
|
|
|
|
|
|
|
|
|
|
|
|
- **ExitLine (ExitMetaCollector / ExitLineReconnector / ExitLineOrchestrator)**
|
|
|
|
|
|
- ファイル:
|
|
|
|
|
|
- `src/mir/builder/control_flow/joinir/merge/exit_line/mod.rs`
|
|
|
|
|
|
- `exit_line/meta_collector.rs`
|
|
|
|
|
|
- `exit_line/reconnector.rs`
|
|
|
|
|
|
- 責務:
|
|
|
|
|
|
- ExitMeta から exit_bindings を構築し(Collector)、
|
|
|
|
|
|
remapper と組み合わせて `builder.variable_map` のキャリアスロットを更新(Reconnector)。
|
|
|
|
|
|
- expr 用の PHI には一切触れない(carrier 専用ライン)。
|
|
|
|
|
|
|
|
|
|
|
|
### 2.4 expr result ライン(式としての戻り値)
|
|
|
|
|
|
|
|
|
|
|
|
- **exit_phi_builder**
|
|
|
|
|
|
- ファイル: `src/mir/builder/control_flow/joinir/merge/exit_phi_builder.rs`
|
|
|
|
|
|
- 責務:
|
|
|
|
|
|
- JoinIR fragment が「式としての戻り値(expr_result)」を持つ場合にだけ、
|
|
|
|
|
|
Return 値を exit block の PHI にまとめて 1 つの `ValueId` を返す(※Phase 33‑16 で正式再実装予定)。
|
|
|
|
|
|
- ループキャリア(`start/end/sum` 等)は扱わない(carrier は ExitLine 専用ライン)。
|
|
|
|
|
|
|
|
|
|
|
|
- **InstructionRewriter(expr_result のみを exit_phi_inputs に流す)**
|
|
|
|
|
|
- ファイル: `instruction_rewriter.rs`
|
|
|
|
|
|
- 責務:
|
|
|
|
|
|
- `JoinFragmentMeta.expr_result` が `Some` の場合だけ、該当 return 値を exit_phi_inputs に積むのが理想形。
|
|
|
|
|
|
- carrier 用の return/jump は ExitMeta/ExitLine 側で扱う。
|
|
|
|
|
|
- **現状(Phase 33‑15 時点)**:
|
|
|
|
|
|
- SSA‑undef を避けるため、一時的に `exit_phi_inputs` / `carrier_inputs` の収集を停止している。
|
|
|
|
|
|
- そのため「ループを式として評価する」ケースでは PHI を経由した expr 結果はまだ生成されない。
|
|
|
|
|
|
- これは **一時的な止血措置** であり、Phase 33‑16 で「Loop ヘッダ PHI を出口値の SSOT とする」設計に差し替える予定。
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 3. JoinIR → MIR 統合の全体フロー
|
|
|
|
|
|
|
|
|
|
|
|
1. Pattern router が AST/LoopFeatures から Pattern1–4 を選択し、各 lowerer が
|
|
|
|
|
|
`(JoinModule, JoinFragmentMeta)` を生成。
|
|
|
|
|
|
2. `JoinInlineBoundary` が:
|
|
|
|
|
|
- ループ入力(join_inputs/host_inputs)
|
|
|
|
|
|
- 条件変数(condition_bindings)
|
|
|
|
|
|
- キャリア出口(exit_bindings)
|
|
|
|
|
|
を保持。
|
|
|
|
|
|
3. `merge_joinir_mir_blocks` が:
|
|
|
|
|
|
- BlockID/ValueID remap
|
|
|
|
|
|
- JoinIR 関数群の inline
|
|
|
|
|
|
- Return→jump の書き換え
|
|
|
|
|
|
- expr result 用 PHI(exit_phi_builder)
|
|
|
|
|
|
- ExitLineOrchestrator(ExitMetaCollector + ExitLineReconnector)
|
|
|
|
|
|
を順に実行。
|
|
|
|
|
|
|
|
|
|
|
|
この全体フローの詳細は `src/mir/builder/control_flow/joinir/merge/mod.rs` と
|
|
|
|
|
|
`phase-189-multi-function-mir-merge/README.md` を参照。
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 4. selfhost / .hako JoinIR Frontend との関係
|
|
|
|
|
|
|
|
|
|
|
|
JoinIR は Rust 側だけでなく、将来的に .hako selfhost コンパイラ側でも生成・解析される予定だよ:
|
|
|
|
|
|
|
|
|
|
|
|
- .hako 側の JsonParser/分析箱は、Program JSON / MIR JSON v1 を読んで JoinIR/MIR を解析する。
|
|
|
|
|
|
- Rust 側 JoinIR ラインの設計変更(特に ValueId/ExitLine/Boundary 周り)は、
|
|
|
|
|
|
**必ずこのファイルを更新してから** .hako 側にも段階的に反映する方針。
|
|
|
|
|
|
|
|
|
|
|
|
「JoinIR の仕様」「箱の責務」「境界の契約」は、このファイルを SSOT として運用していく。
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 5. 関連ドキュメント
|
|
|
|
|
|
|
|
|
|
|
|
- `docs/development/current/main/10-Now.md`
|
|
|
|
|
|
- 全体の「いまどこ」を短くまとめたダッシュボード。
|
|
|
|
|
|
- `docs/private/roadmap2/phases/phase-180-joinir-unification-before-selfhost/README.md`
|
|
|
|
|
|
- JoinIR 統一フェーズ全体のロードマップと進捗。
|
|
|
|
|
|
- 各 Phase 詳細:
|
|
|
|
|
|
- 185–188: Strict mode / LoopBuilder 削除 / Pattern1–4 基盤
|
|
|
|
|
|
- 189–193: Multi-function merge / Select bridge / ExitLine 箱化
|
|
|
|
|
|
- 171–172 / 33‑10/13: ConditionEnv, ConditionBinding, JoinFragmentMeta, ExitLineRefactor 等
|
2025-12-08 03:06:20 +09:00
|
|
|
|
- `docs/development/current/main/loop_pattern_space.md`
|
|
|
|
|
|
- JoinIR ループパターン空間の整理メモ。
|
|
|
|
|
|
どの軸(継続条件 / break / continue / PHI / 条件変数スコープ / 更新パターン)でパターンを分けるか、
|
|
|
|
|
|
そして P1–P4 / Trim(P5) の位置づけと、今後追加候補のパターン一覧がまとまっている。
|