feat(joinir): Phase 33-22 CommonPatternInitializer & JoinIRConversionPipeline integration

Unifies initialization and conversion logic across all 4 loop patterns,
eliminating code duplication and establishing single source of truth.

## Changes

### Infrastructure (New)
- CommonPatternInitializer (117 lines): Unified loop var extraction + CarrierInfo building
- JoinIRConversionPipeline (127 lines): Unified JoinIR→MIR→Merge flow

### Pattern Refactoring
- Pattern 1: Uses CommonPatternInitializer + JoinIRConversionPipeline (-25 lines)
- Pattern 2: Uses CommonPatternInitializer + JoinIRConversionPipeline (-25 lines)
- Pattern 3: Uses CommonPatternInitializer + JoinIRConversionPipeline (-25 lines)
- Pattern 4: Uses CommonPatternInitializer + JoinIRConversionPipeline (-40 lines)

### Code Reduction
- Total reduction: ~115 lines across all patterns
- Zero code duplication in initialization/conversion
- Pattern files: 806 lines total (down from ~920)

### Quality Improvements
- Single source of truth for initialization
- Consistent conversion flow across all patterns
- Guaranteed boundary.loop_var_name setting (prevents SSA-undef bugs)
- Improved maintainability and testability

### Testing
- All 4 patterns tested and passing:
  - Pattern 1 (Simple While): 
  - Pattern 2 (With Break): 
  - Pattern 3 (If-Else PHI): 
  - Pattern 4 (With Continue): 

### Documentation
- Phase 33-22 inventory and results document
- Updated joinir-architecture-overview.md with new infrastructure

## Breaking Changes
None - pure refactoring with no API changes

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
This commit is contained in:
nyash-codex
2025-12-07 21:02:20 +09:00
parent 404c831963
commit 4e32a803a7
32 changed files with 6378 additions and 225 deletions

View File

@ -0,0 +1,204 @@
# JoinIR Architecture Overview (20251206)
このドキュメントは、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`)の出口は **ExitLineExitMeta / ExitBinding / ExitLineReconnector** だけが扱う。
4. **ループ制御 vs 条件式の分離**
- ループの「形」Pattern14, LoopFeaturesは control-flow 専用の箱が担当。
- 条件式(`i < len && (ch == " " || ch == "\t")` 等)は **BoolExprLowerer / condition_to_joinir** が担当し、
ループパターンは boolean ValueId だけを受け取る。
5. **FailFast**
- JoinIR が対応していないループパターン / if パターンは、必ず `[joinir/freeze]` 等で明示的にエラーにする。
- LoopBuilder 等へのサイレントフォールバックは禁止Phase 186187 で完全削除済み)。
---
## 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)` で Pattern14 に分類。
- `LOOP_PATTERNS` テーブルを通じて該当 lowererpattern*_minimal.rsにルーティング。
- Phase 170C 系で `LoopUpdateSummary`(各キャリアの UpdateKind 情報)を統合し、
`CaseALoweringShape` が関数名ではなく構造+更新パターンだけを見て判定できるようにする計画。
- **Pattern Lowerers (Pattern14)**
- ファイル例:
- `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 に記録する。
### 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 3316 で正式再実装予定)。
- ループキャリア(`start/end/sum`は扱わないcarrier は ExitLine 専用ライン)。
- **InstructionRewriterexpr_result のみを exit_phi_inputs に流す)**
- ファイル: `instruction_rewriter.rs`
- 責務:
- `JoinFragmentMeta.expr_result``Some` の場合だけ、該当 return 値を exit_phi_inputs に積むのが理想形。
- carrier 用の return/jump は ExitMeta/ExitLine 側で扱う。
- **現状Phase 3315 時点)**:
- SSAundef を避けるため、一時的に `exit_phi_inputs` / `carrier_inputs` の収集を停止している。
- そのため「ループを式として評価する」ケースでは PHI を経由した expr 結果はまだ生成されない。
- これは **一時的な止血措置** であり、Phase 3316 で「Loop ヘッダ PHI を出口値の SSOT とする」設計に差し替える予定。
---
## 3. JoinIR → MIR 統合の全体フロー
1. Pattern router が AST/LoopFeatures から Pattern14 を選択し、各 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 用 PHIexit_phi_builder
- ExitLineOrchestratorExitMetaCollector + 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 詳細:
- 185188: Strict mode / LoopBuilder 削除 / Pattern14 基盤
- 189193: Multi-function merge / Select bridge / ExitLine 箱化
- 171172 / 3310/13: ConditionEnv, ConditionBinding, JoinFragmentMeta, ExitLineRefactor 等