2025-12-08 04:00:44 +09:00
|
|
|
|
# JoinIR Architecture Overview (2025‑12‑08)
|
2025-12-07 21:02:20 +09:00
|
|
|
|
|
|
|
|
|
|
このドキュメントは、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` に一本化する。
|
|
|
|
|
|
|
2025-12-08 04:00:44 +09:00
|
|
|
|
3. **LoopHeader PHI を SSA の単一源泉にする**
|
|
|
|
|
|
- ループ変数とキャリアは **LoopHeaderPhiBuilder/LoopHeaderPhiInfo** でヘッダ PHI を作り、これを「現在値」の SSOT にする。
|
|
|
|
|
|
- exit 用の PHI も組むが、変数再接続や expr_result 収集はヘッダ PHI を経由して行う(SSA‑undef 防止)。
|
|
|
|
|
|
|
|
|
|
|
|
4. **式としての戻り値とキャリア更新を分離する**
|
2025-12-07 21:02:20 +09:00
|
|
|
|
- 「ループが式として値を返す」ケース(例: `let r = loop_min_while(...)`)の出口は **exit_phi_builder** が扱う。
|
|
|
|
|
|
- 「ループが状態更新だけする」ケース(例: `trim` の `start/end`)の出口は **ExitLine(ExitMeta / ExitBinding / ExitLineReconnector)** だけが扱う。
|
|
|
|
|
|
|
2025-12-08 04:00:44 +09:00
|
|
|
|
5. **ループ制御 vs 条件式の分離**
|
2025-12-07 21:02:20 +09:00
|
|
|
|
- ループの「形」(Pattern1–4, LoopFeatures)は control-flow 専用の箱が担当。
|
|
|
|
|
|
- 条件式(`i < len && (ch == " " || ch == "\t")` 等)は **BoolExprLowerer / condition_to_joinir** が担当し、
|
|
|
|
|
|
ループパターンは boolean ValueId だけを受け取る。
|
|
|
|
|
|
|
2025-12-08 04:00:44 +09:00
|
|
|
|
6. **Fail‑Fast**
|
2025-12-07 21:02:20 +09:00
|
|
|
|
- JoinIR が対応していないループパターン / if パターンは、必ず `[joinir/freeze]` 等で明示的にエラーにする。
|
2025-12-08 04:00:44 +09:00
|
|
|
|
- LoopBuilder 等へのサイレントフォールバックは禁止。
|
2025-12-07 21:02:20 +09:00
|
|
|
|
|
2025-12-08 18:36:13 +09:00
|
|
|
|
7. **Param の役割(ParamRole)を分ける**
|
|
|
|
|
|
- JoinIR 側で扱うパラメータは概念的に 3 種類に分かれる:
|
|
|
|
|
|
- 条件専用(Condition param): 継続条件や break 条件だけに使う値
|
|
|
|
|
|
- キャリア(Carrier param): ループ状態(pos/result など)として更新される値
|
|
|
|
|
|
- 式結果(Expr param): ループが式として返す値
|
|
|
|
|
|
- ExitLine / Header PHI / InstructionRewriter は **Carrier param だけ** を対象にし、Condition/Expr param は上書きしない。
|
|
|
|
|
|
- 現状は ConditionBinding/ExitMeta/JoinFragmentMeta で役割を区別しており、将来 ParamRole enum として明示する予定。
|
|
|
|
|
|
|
|
|
|
|
|
8. **LoopHeader PHI dst は予約領域(上書き禁止)**
|
|
|
|
|
|
- LoopHeaderPhiBuilder が生成したヘッダ PHI の dst ValueId は「現在のループ値」の SSOT として扱い、
|
|
|
|
|
|
BoundaryInjector や InstructionRewriter が `Copy` などで二度書きすることを禁止する。
|
|
|
|
|
|
- merge ラインでは「ヘッダ PHI dst に対する新しい定義が出てきたら debug モードで panic する」ことで契約違反を早期検出する。
|
|
|
|
|
|
|
2025-12-07 21:02:20 +09:00
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 2. 主な箱と責務
|
|
|
|
|
|
|
|
|
|
|
|
### 2.1 Loop 構造・検出ライン
|
|
|
|
|
|
|
|
|
|
|
|
- **LoopFeatures / LoopPatternKind / router**
|
|
|
|
|
|
- ファイル:
|
|
|
|
|
|
- `src/mir/loop_pattern_detection.rs`
|
|
|
|
|
|
- `src/mir/builder/control_flow/joinir/patterns/router.rs`
|
2025-12-08 04:00:44 +09:00
|
|
|
|
- `src/mir/builder/control_flow/joinir/patterns/ast_feature_extractor.rs`
|
2025-12-07 21:02:20 +09:00
|
|
|
|
- 責務:
|
2025-12-08 04:00:44 +09:00
|
|
|
|
- AST から break/continue/if‑else PHI などの特徴を抽出(ast_feature_extractor)。
|
|
|
|
|
|
- `classify(&LoopFeatures)` で Pattern1–4 に分類し、テーブル駆動の `LOOP_PATTERNS` でルーティング。
|
|
|
|
|
|
- ルータ順序は P4(continue) → P3(if‑phi) → P1(simple) → P2(break) で固定(優先度フィールドはデバッグ用)。
|
2025-12-07 21:02:20 +09:00
|
|
|
|
|
|
|
|
|
|
- **Pattern Lowerers (Pattern1–4)**
|
|
|
|
|
|
- ファイル例:
|
2025-12-08 04:00:44 +09:00
|
|
|
|
- `pattern1_minimal.rs`(Simple while)
|
|
|
|
|
|
- `pattern2_with_break.rs`(break 付き / Trim 昇格パスを含む)
|
|
|
|
|
|
- `pattern3_with_if_phi.rs`(if‑phi キャリア)
|
|
|
|
|
|
- `pattern4_with_continue.rs`(continue を Select で表現)
|
2025-12-07 21:02:20 +09:00
|
|
|
|
- 責務:
|
|
|
|
|
|
- LoopScopeShape / AST / LoopFeatures を入力として JoinIR の `JoinModule` を構築。
|
|
|
|
|
|
- `JoinFragmentMeta{ expr_result, exit_meta }` を返し、出口情報を ExitLine に渡す。
|
|
|
|
|
|
- host/MIR の ValueId は一切扱わない(JoinIR ローカルの ValueId のみ)。
|
|
|
|
|
|
|
2025-12-08 04:00:44 +09:00
|
|
|
|
- **Scope / Env Builders**
|
|
|
|
|
|
- `loop_scope_shape_builder.rs`: ループ本体ローカルの収集、LoopScopeShape 統一生成。
|
|
|
|
|
|
- `condition_env_builder.rs`: 条件専用変数の環境と ConditionBinding を一括構築。
|
|
|
|
|
|
|
2025-12-07 21:02:20 +09:00
|
|
|
|
- **CommonPatternInitializer** (Phase 33-22)
|
|
|
|
|
|
- ファイル: `src/mir/builder/control_flow/joinir/patterns/common_init.rs`
|
|
|
|
|
|
- 責務:
|
|
|
|
|
|
- 全 Pattern 共通の初期化ロジック統一化(ループ変数抽出 + CarrierInfo 構築)。
|
2025-12-08 04:00:44 +09:00
|
|
|
|
- 全パターンで boundary.loop_var_name を確実に設定し、SSA‑undef を防ぐ。
|
2025-12-07 21:02:20 +09:00
|
|
|
|
|
2025-12-08 19:51:04 +09:00
|
|
|
|
- **PatternPipelineContext** (Phase 179-B)
|
|
|
|
|
|
- ファイル: `src/mir/builder/control_flow/joinir/patterns/pattern_pipeline.rs`
|
|
|
|
|
|
- 責務:
|
|
|
|
|
|
- 全 Pattern の前処理結果を格納する「解析済みコンテキスト箱」。
|
|
|
|
|
|
- CommonPatternInitializer + LoopScopeShapeBuilder の結果を統一的に保持。
|
|
|
|
|
|
- Pattern 1-4 の共通データ(loop_var_name, loop_var_id, carrier_info, loop_scope)を提供。
|
|
|
|
|
|
- Pattern 2/4 専用データ(condition_env, carrier_updates, trim_helper)は Option<T> で保持。
|
|
|
|
|
|
- **Analyzer-only dependencies**: 解析ロジックのみ依存、JoinIR emission ロジックは含まない。
|
2025-12-08 21:09:00 +09:00
|
|
|
|
|
|
|
|
|
|
- **TrimLoopLowerer (P5 Dedicated Module)** (Phase 180)
|
|
|
|
|
|
- ファイル: `src/mir/builder/control_flow/joinir/patterns/trim_loop_lowering.rs`
|
|
|
|
|
|
- 責務:
|
|
|
|
|
|
- Trim/CharComparison (Pattern 5) 専用の lowering ロジックを一箇所に集約。
|
|
|
|
|
|
- Pattern2/4 から呼ばれ、LoopBodyLocal 変数を carrier に昇格し、Trim パターンの break 条件を置き換える。
|
|
|
|
|
|
- TrimPatternValidator/TrimPatternLowerer を内部で利用し、carrier 初期化コード生成・条件式置換を実行。
|
|
|
|
|
|
- 入力:
|
|
|
|
|
|
- MirBuilder, LoopScopeShape, loop_cond, break_cond, body, loop_var_name, carrier_info, alloc_join_value
|
|
|
|
|
|
- 出力:
|
|
|
|
|
|
- `Some(TrimLoweringResult)`: Trim パターン検出・lowering 成功時(置換後条件、更新 carrier_info、condition_bindings)
|
|
|
|
|
|
- `None`: Trim パターンでない場合(通常ループ処理に戻る)
|
|
|
|
|
|
- `Err`: Trim パターン検出したが lowering 失敗時
|
|
|
|
|
|
- 使用元:
|
|
|
|
|
|
- Pattern2 (pattern2_with_break.rs): Trim/P5 ロジックを完全委譲(~160 行削減)
|
|
|
|
|
|
- Pattern4 (pattern4_with_continue.rs): 将来の Phase 172+ で Trim lowering 実装時に利用予定
|
2025-12-08 19:51:04 +09:00
|
|
|
|
- デザイン原則:
|
|
|
|
|
|
- Pure analysis container(前処理結果のみ保持、emission なし)
|
|
|
|
|
|
- Pattern-specific variants(Option<T> でパターン固有データ管理)
|
|
|
|
|
|
- Single source of truth(全パターンが同じ前処理経路を使用)
|
|
|
|
|
|
|
2025-12-07 21:02:20 +09:00
|
|
|
|
- **JoinIRConversionPipeline** (Phase 33-22)
|
|
|
|
|
|
- ファイル: `src/mir/builder/control_flow/joinir/patterns/conversion_pipeline.rs`
|
|
|
|
|
|
- 責務:
|
|
|
|
|
|
- JoinIR → MIR 変換フロー統一化(JoinModule → MirModule → merge_joinir_mir_blocks)。
|
2025-12-08 04:00:44 +09:00
|
|
|
|
- JoinIR/MIR の関数数・ブロック数をログ出力し、全パターンが同じ入口でマージする。
|
2025-12-07 21:02:20 +09:00
|
|
|
|
|
|
|
|
|
|
### 2.2 条件式ライン(式の箱)
|
|
|
|
|
|
|
2025-12-08 04:00:44 +09:00
|
|
|
|
- **BoolExprLowerer / condition_to_joinir**
|
|
|
|
|
|
- ファイル:
|
|
|
|
|
|
- `src/mir/join_ir/lowering/bool_expr_lowerer.rs`
|
|
|
|
|
|
- `src/mir/join_ir/lowering/condition_to_joinir.rs`
|
2025-12-07 21:02:20 +09:00
|
|
|
|
- 責務:
|
2025-12-08 04:00:44 +09:00
|
|
|
|
- 通常の if/while 条件を MIR Compare/BinOp/UnaryOp へ lowering。
|
|
|
|
|
|
- ループ lowerer 用の「AST 条件 → JoinIR Compute 命令列」を ConditionEnv とセットで構築。
|
2025-12-07 21:02:20 +09:00
|
|
|
|
|
2025-12-08 04:00:44 +09:00
|
|
|
|
- **ConditionEnv/ConditionBinding + ConditionEnvBuilder**
|
|
|
|
|
|
- ファイル:
|
|
|
|
|
|
- `src/mir/join_ir/lowering/condition_env.rs`
|
|
|
|
|
|
- `src/mir/builder/control_flow/joinir/patterns/condition_env_builder.rs`
|
2025-12-07 21:02:20 +09:00
|
|
|
|
- 責務:
|
2025-12-08 04:00:44 +09:00
|
|
|
|
- 変数名→JoinIR ValueId の環境を組み立て、host↔join の橋渡しを ConditionBinding に明示する。
|
|
|
|
|
|
- Pattern 2 では break 条件の全変数をスキャンし、JoinInlineBoundary.condition_bindings に渡す。
|
2025-12-07 21:02:20 +09:00
|
|
|
|
|
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
|
|
|
|
- 責務:
|
2025-12-08 04:00:44 +09:00
|
|
|
|
- 条件式の各変数を LoopParam / OuterLocal / LoopBodyLocal に分類。
|
|
|
|
|
|
- 関数パラメータ誤分類バグは `condition_var_analyzer.rs` の修正で解消済み(OuterLocal として扱う)。
|
2025-12-07 23:09:25 +09:00
|
|
|
|
|
2025-12-08 04:00:44 +09:00
|
|
|
|
- **LoopBodyCarrierPromoter(Phase 171-C-2 実装済み)**
|
2025-12-07 23:09:25 +09:00
|
|
|
|
- ファイル: `src/mir/loop_pattern_detection/loop_body_carrier_promoter.rs`
|
|
|
|
|
|
- 責務:
|
2025-12-08 04:00:44 +09:00
|
|
|
|
- LoopBodyLocal を Trim パターンとして bool キャリアへ昇格(substring + equality 連鎖を検出)。
|
|
|
|
|
|
- 昇格成功 → CarrierInfo に統合し Pattern 2/4 へ橋渡し。昇格失敗は Fail‑Fast。
|
|
|
|
|
|
- Pattern 2 は安全な Trim なら実際に前処理(substring 生成 + 空白比較の初期化)を emit してから JoinIR lowering。
|
|
|
|
|
|
- Pattern 4 は Trim 昇格が起きた場合はガード付きでエラーにし、未実装を明示(Fail‑Fast)。
|
2025-12-08 13:08:44 +09:00
|
|
|
|
- 汎用性:
|
|
|
|
|
|
- Phase 173 で `_skip_whitespace`(JsonParser)が Trim パターンで動作確認済み。
|
|
|
|
|
|
- Phase 174 で `_parse_string` 最小化版(終端クォート検出)でも動作確認済み。
|
|
|
|
|
|
- → 空白文字以外の文字比較ループにも対応可能(TrimLoopHelper の汎用性実証)。
|
2025-12-08 04:00:44 +09:00
|
|
|
|
|
|
|
|
|
|
- **ContinueBranchNormalizer / LoopUpdateAnalyzer**
|
|
|
|
|
|
- ファイル:
|
|
|
|
|
|
- `src/mir/join_ir/lowering/continue_branch_normalizer.rs`
|
|
|
|
|
|
- `src/mir/join_ir/lowering/loop_update_analyzer.rs`
|
|
|
|
|
|
- 責務:
|
|
|
|
|
|
- else-continue を then-continue へ正規化し、Select ベースの continue を簡潔にする。
|
|
|
|
|
|
- ループ本体で実際に更新されるキャリアだけを抽出(Pattern 4 で不要キャリアを排除)。
|
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`
|
2025-12-08 04:00:44 +09:00
|
|
|
|
- `src/mir/join_ir/lowering/loop_update_analyzer.rs`
|
2025-12-07 21:02:20 +09:00
|
|
|
|
- 責務:
|
2025-12-08 04:00:44 +09:00
|
|
|
|
- ループで更新される変数(carrier)を検出し、UpdateExpr を保持。
|
|
|
|
|
|
- Pattern 4 では実際に更新されるキャリアだけを残す。
|
2025-12-07 21:02:20 +09:00
|
|
|
|
|
|
|
|
|
|
- **ExitMeta / JoinFragmentMeta**
|
2025-12-08 04:00:44 +09:00
|
|
|
|
- ファイル: `carrier_info.rs`
|
2025-12-07 21:02:20 +09:00
|
|
|
|
- 責務:
|
2025-12-08 04:00:44 +09:00
|
|
|
|
- JoinIR lowerer が出口の JoinIR ValueId を記録(expr_result とキャリアを明確に分離)。
|
2025-12-07 21:02:20 +09:00
|
|
|
|
|
2025-12-08 04:00:44 +09:00
|
|
|
|
- **LoopHeader PHI Builder**
|
|
|
|
|
|
- ファイル:
|
|
|
|
|
|
- `src/mir/builder/control_flow/joinir/merge/loop_header_phi_info.rs`
|
|
|
|
|
|
- `loop_header_phi_builder.rs`
|
2025-12-07 21:02:20 +09:00
|
|
|
|
- 責務:
|
2025-12-08 04:00:44 +09:00
|
|
|
|
- ループ変数とキャリアの PHI をヘッダブロックに生成し、entry/latch の 2 入力で SSA を確立。
|
|
|
|
|
|
- instruction_rewriter が latch 側を埋めた後に finalize して挿入する。
|
2025-12-07 21:02:20 +09:00
|
|
|
|
|
|
|
|
|
|
- **JoinInlineBoundary**
|
|
|
|
|
|
- ファイル: `src/mir/join_ir/lowering/inline_boundary.rs`
|
2025-12-08 04:00:44 +09:00
|
|
|
|
- 主フィールド:
|
2025-12-07 21:02:20 +09:00
|
|
|
|
- `join_inputs / host_inputs`:ループパラメータの橋渡し
|
2025-12-08 04:00:44 +09:00
|
|
|
|
- `condition_bindings`:条件専用変数の橋渡し(JoinIR ValueId を明示)
|
|
|
|
|
|
- `exit_bindings`:キャリア出口の橋渡し(carrier 名を明示)
|
|
|
|
|
|
- `expr_result` / `loop_var_name`:expr result / ヘッダ PHI 生成用のメタ情報
|
2025-12-07 21:02:20 +09:00
|
|
|
|
- 責務:
|
2025-12-08 04:00:44 +09:00
|
|
|
|
- 「host ↔ JoinIR」の境界情報の SSOT。各パターン lowerer がここに全て詰めてから merge する。
|
2025-12-07 21:02:20 +09:00
|
|
|
|
|
|
|
|
|
|
- **BoundaryInjector**
|
|
|
|
|
|
- ファイル: `src/mir/builder/joinir_inline_boundary_injector.rs`
|
|
|
|
|
|
- 責務:
|
2025-12-08 04:00:44 +09:00
|
|
|
|
- `join_inputs` と `condition_bindings` を entry block に Copy で注入し、JoinIR ローカル ID と host ID を接続。
|
2025-12-07 21:02:20 +09:00
|
|
|
|
|
|
|
|
|
|
- **ExitLine (ExitMetaCollector / ExitLineReconnector / ExitLineOrchestrator)**
|
|
|
|
|
|
- ファイル:
|
|
|
|
|
|
- `src/mir/builder/control_flow/joinir/merge/exit_line/mod.rs`
|
|
|
|
|
|
- `exit_line/meta_collector.rs`
|
|
|
|
|
|
- `exit_line/reconnector.rs`
|
|
|
|
|
|
- 責務:
|
2025-12-08 04:00:44 +09:00
|
|
|
|
- ExitMeta から exit_bindings を構築(Collector)。
|
|
|
|
|
|
- 変数再接続はヘッダ PHI の dst を使って `builder.variable_map` を更新(Reconnector)。
|
2025-12-07 21:02:20 +09:00
|
|
|
|
- expr 用の PHI には一切触れない(carrier 専用ライン)。
|
|
|
|
|
|
|
2025-12-08 06:14:03 +09:00
|
|
|
|
- **JoinInlineBoundaryBuilder(Phase 200-2 / Phase 201 完了)**
|
2025-12-08 04:35:13 +09:00
|
|
|
|
- ファイル: `src/mir/join_ir/lowering/inline_boundary_builder.rs`
|
|
|
|
|
|
- 責務:
|
|
|
|
|
|
- JoinInlineBoundary の構築を Builder パターンで統一化。
|
|
|
|
|
|
- フィールド直書きの散乱を防ぎ、inputs/outputs/condition_bindings/exit_bindings/loop_var_name/expr_result の設定を fluent API で実施。
|
2025-12-08 06:14:03 +09:00
|
|
|
|
- **Phase 201 で Pattern1/2/3/4 全てに適用完了**(境界情報組み立てを 1 箇所に集約)。
|
2025-12-08 04:35:13 +09:00
|
|
|
|
|
|
|
|
|
|
- **JoinIRVerifier(Phase 200-3 追加)**
|
|
|
|
|
|
- ファイル: `src/mir/builder/control_flow/joinir/merge/mod.rs`(debug_assertions 専用関数)
|
|
|
|
|
|
- 責務:
|
|
|
|
|
|
- LoopHeader PHI / ExitLine 契約をデバッグビルドで検証する門番。
|
|
|
|
|
|
- `verify_loop_header_phis()`: loop_var_name がある場合にヘッダ PHI が存在するか確認。
|
|
|
|
|
|
- `verify_exit_line()`: exit_bindings が exit block に対応しているか確認。
|
|
|
|
|
|
- `verify_joinir_contracts()`: merge_joinir_mir_blocks() の最後で全契約を一括チェック。
|
|
|
|
|
|
- release ビルドでは完全に除去される(`#[cfg(debug_assertions)]`)。
|
|
|
|
|
|
|
2025-12-07 21:02:20 +09:00
|
|
|
|
### 2.4 expr result ライン(式としての戻り値)
|
|
|
|
|
|
|
|
|
|
|
|
- **exit_phi_builder**
|
|
|
|
|
|
- ファイル: `src/mir/builder/control_flow/joinir/merge/exit_phi_builder.rs`
|
|
|
|
|
|
- 責務:
|
2025-12-08 04:00:44 +09:00
|
|
|
|
- JoinIR fragment が `expr_result` を持つときに exit ブロックへ PHI を生成。
|
|
|
|
|
|
- carrier_inputs も受け取り exit ブロックに PHI を作るが、再接続の SSOT は LoopHeader PHI(ExitLine はヘッダ PHI を使用)。
|
2025-12-07 21:02:20 +09:00
|
|
|
|
|
2025-12-08 04:00:44 +09:00
|
|
|
|
- **InstructionRewriter**
|
2025-12-07 21:02:20 +09:00
|
|
|
|
- ファイル: `instruction_rewriter.rs`
|
|
|
|
|
|
- 責務:
|
2025-12-08 04:00:44 +09:00
|
|
|
|
- continuation 関数(k_exit)をスキップし、Return → exit ブロック Jump に変換。
|
|
|
|
|
|
- `JoinFragmentMeta.expr_result` と exit_bindings をヘッダ PHI 経由で収集し、`exit_phi_inputs` / `carrier_inputs` を復活させた(SSA‑undef 修正済み)。
|
|
|
|
|
|
- tail call を Branch/Jump に書き換えつつ、LoopHeaderPhiInfo に latch 入力を記録する。
|
2025-12-07 21:02:20 +09:00
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 3. JoinIR → MIR 統合の全体フロー
|
|
|
|
|
|
|
|
|
|
|
|
1. Pattern router が AST/LoopFeatures から Pattern1–4 を選択し、各 lowerer が
|
|
|
|
|
|
`(JoinModule, JoinFragmentMeta)` を生成。
|
|
|
|
|
|
2. `JoinInlineBoundary` が:
|
|
|
|
|
|
- ループ入力(join_inputs/host_inputs)
|
|
|
|
|
|
- 条件変数(condition_bindings)
|
|
|
|
|
|
- キャリア出口(exit_bindings)
|
|
|
|
|
|
を保持。
|
2025-12-08 04:00:44 +09:00
|
|
|
|
3. `merge_joinir_mir_blocks` が(マルチ関数対応):
|
|
|
|
|
|
- 全関数の BlockID を再割り当て(block_allocator)し、ValueId はパラメータを除外して収集。
|
|
|
|
|
|
- Boundary の condition/exit Bindings の JoinIR ValueId も remap 対象に追加。
|
|
|
|
|
|
- LoopHeader PHI を生成(loop_header_phi_builder)し、latch 側は instruction_rewriter が埋める。
|
|
|
|
|
|
- instruction_rewriter で関数をマージしつつ Call→Jump に変換、k_exit 関数はスキップ。
|
|
|
|
|
|
- BoundaryInjector で entry block に Copy を注入(join_inputs + condition_bindings)。
|
|
|
|
|
|
- Header PHI を finalize → exit_phi_builder で expr_result/carrier の exit PHI を構築。
|
|
|
|
|
|
- ExitLineOrchestrator がヘッダ PHI dst を使って variable_map を更新。
|
|
|
|
|
|
- host の現在ブロックから JoinIR entry へ jump を張り、exit ブロックに切り替える。
|
2025-12-07 21:02:20 +09:00
|
|
|
|
|
|
|
|
|
|
この全体フローの詳細は `src/mir/builder/control_flow/joinir/merge/mod.rs` と
|
|
|
|
|
|
`phase-189-multi-function-mir-merge/README.md` を参照。
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
2025-12-08 21:41:19 +09:00
|
|
|
|
## 4. JsonParser / Trim / P5 ループの現在地(Phase 170–181)
|
|
|
|
|
|
|
|
|
|
|
|
### 4.1 JsonParser ループ空間と P1–P5
|
|
|
|
|
|
|
|
|
|
|
|
Phase 181 で JsonParserBox 内の 11 ループを棚卸しした結果、
|
|
|
|
|
|
構造的には **すべて JoinIR Pattern1–4 (+ P5) で扱える** ことが分かったよ。
|
|
|
|
|
|
|
|
|
|
|
|
- 既に JoinIR 経路で動作しているもの:
|
|
|
|
|
|
- `_skip_whitespace`(P2 + P5 Trim)
|
|
|
|
|
|
- `_trim` leading/trailing(P2 + P5 Trim)
|
|
|
|
|
|
- **Phase 182 で P1/P2 パターン検証完了** ✅:
|
|
|
|
|
|
- Pattern1 (Simple): `_match_literal` 系ループで動作確認済み(apps/tests/phase182_p1_match_literal.hako)
|
|
|
|
|
|
- Pattern2 (Break): 整数演算ループで動作確認済み(apps/tests/phase182_p2_break_integer.hako)
|
|
|
|
|
|
- **ブロッカー発見**: 実際の JsonParser ループには 2 つの制約が必要:
|
|
|
|
|
|
1. LoopBodyLocal 変数の扱い(`ch`, `digit_pos`, `pos` など)
|
|
|
|
|
|
- 現状は Trim pattern 専用の carrier 昇格を試みてエラーになる
|
|
|
|
|
|
- P1/P2 では純粋なローカル変数(昇格不要)として扱うべき
|
|
|
|
|
|
2. 文字列連結フィルタ(Phase 178)
|
|
|
|
|
|
- `num_str = num_str + ch` のような string concat を保守的に reject
|
|
|
|
|
|
- JsonParser では必須の操作なので段階的に有効化が必要
|
|
|
|
|
|
- 構造的に P1–P4 で対応可能(代表例):
|
|
|
|
|
|
- `_parse_number` / `_atoi`(P2 Break)- Phase 182 でブロッカー特定済み
|
|
|
|
|
|
- `_match_literal`(P1 Simple while)- Phase 182 で動作確認済み ✅
|
|
|
|
|
|
- `_parse_string` / `_parse_array` / `_parse_object`
|
|
|
|
|
|
(P2 + P4 + P5 の組み合わせで表現可能なことを設計上確認済み)
|
|
|
|
|
|
- 低優先度だが理論上は P1–P4 からの拡張で吸収可能:
|
|
|
|
|
|
- `_unescape_string` など、複雑な continue / 条件付き更新を含むループ
|
|
|
|
|
|
|
|
|
|
|
|
方針:
|
|
|
|
|
|
|
|
|
|
|
|
- **ループの「形」は P1–P4 から増やさない**。
|
|
|
|
|
|
複雑さ(LoopBodyLocal 条件、OR chain、continue 多用など)は BoolExprLowerer /
|
|
|
|
|
|
ContinueBranchNormalizer / TrimLoopLowerer (P5) といった補助箱側で吸収する。
|
|
|
|
|
|
- JsonParser 側の P5 適用(Trim / `_skip_whitespace` / `_parse_string` 最小版)は実証済み。
|
|
|
|
|
|
残りのループは Phase 17x–18x で、P1–P4+P5 の組み合わせとして段階的に実装していく。
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 5. selfhost / .hako JoinIR Frontend との関係
|
2025-12-07 21:02:20 +09:00
|
|
|
|
|
|
|
|
|
|
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) の位置づけと、今後追加候補のパターン一覧がまとまっている。
|
2025-12-08 15:17:53 +09:00
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## 6. Roadmap(JoinIR の今後のゴール)
|
|
|
|
|
|
|
|
|
|
|
|
ここから先の JoinIR の「目指す形」を、箱レベルでざっくり書いておくよ。フェーズ詳細は各 phase ドキュメントに分散させて、このセクションは常に最新の方向性だけを保つ。
|
|
|
|
|
|
|
|
|
|
|
|
### 6.1 直近(Phase 176-177 まわり)
|
|
|
|
|
|
|
|
|
|
|
|
- **P5(Trim/JsonParser 系)ループの複数キャリア対応** ✅ Phase 176 完了 (2025-12-08)
|
|
|
|
|
|
- 完了内容:
|
|
|
|
|
|
- Pattern2 lowerer を全キャリア対応に拡張(ヘッダ PHI / ループ更新 / ExitLine)。
|
|
|
|
|
|
- CarrierUpdateLowerer ヘルパで UpdateExpr → JoinIR 変換を統一。
|
|
|
|
|
|
- 2キャリア(pos + result)E2E テスト完全成功。
|
|
|
|
|
|
- 技術的成果:
|
|
|
|
|
|
- CarrierInfo / ExitMeta / ExitLine / LoopHeaderPhiBuilder の multi-carrier 対応を Pattern2 lowerer で完全活用。
|
|
|
|
|
|
- Trim pattern の「キャリア = ループ変数」という誤解を解消(loop_var は特殊キャリア)。
|
|
|
|
|
|
- 次のステップ (Phase 177):
|
|
|
|
|
|
- JsonParser `_parse_string` 本体を P2+P5 で通す(pos + result の 2 キャリアで実ループ動作確認)。
|
|
|
|
|
|
|
|
|
|
|
|
### 6.2 中期(selfhost depth‑2 / JsonParser 本体)
|
|
|
|
|
|
|
|
|
|
|
|
- **JsonParserBox / Trim 系ループの本線化**
|
|
|
|
|
|
- 目標:
|
|
|
|
|
|
- `_trim` / `_skip_whitespace` / `_parse_string` / `_parse_array` などの主要ループが、すべて JoinIR Pattern1–4 + P5 で通ること。
|
|
|
|
|
|
- LoopConditionScopeBox + LoopBodyCarrierPromoter + TrimLoopHelper の上で安全に正規化できるループを広げていく。
|
|
|
|
|
|
- 方針:
|
|
|
|
|
|
- 「ループの形」は P1–P4 から増やさず、複雑さは BoolExprLowerer / ContinueBranchNormalizer / P5 系の補助箱で吸収する。
|
|
|
|
|
|
- LoopPatternSpace の P6/P7/P12 候補(break+continue 同時 / 複数キャリア条件更新 / early return)は、実アプリで必要になった順に小さく足す。
|
|
|
|
|
|
|
|
|
|
|
|
- **selfhost depth‑2(.hako JoinIR/MIR Frontend)**
|
|
|
|
|
|
- 目標:
|
|
|
|
|
|
- `.hako → JsonParserBox → Program/MIR JSON → MirAnalyzerBox/JoinIrAnalyzerBox → VM/LLVM` の深度 2 ループを、日常的に回せるようにする。
|
|
|
|
|
|
- Rust 側の JoinIR は「JSON を受け取って実行・検証するランナー層」、.hako 側が「JoinIR/MIR を構築・解析する言語側 SSOT」という役割分担に近づける。
|
|
|
|
|
|
- 前提:
|
|
|
|
|
|
- 本ドキュメント(joinir-architecture-overview.md)を .hako 側の JoinIR 実装の参照設計として維持し、仕様変更は必ずここを更新してから .hako にも反映する。
|
|
|
|
|
|
|
|
|
|
|
|
### 6.3 当面やらないこと(Non‑Goals)
|
|
|
|
|
|
|
|
|
|
|
|
- ループパターンを闇雲に増やすこと
|
|
|
|
|
|
- P1–P4(構造)+ P5(body‑local 条件を昇格する補助パス)を「骨格」とみなし、
|
|
|
|
|
|
新しいパターンが必要になったときは LoopPatternSpace に追記してから、小さな箱で補う方針。
|
|
|
|
|
|
- LoopBuilder の復活や、JoinIR 以外の別ラインによるループ lowering
|
|
|
|
|
|
- LoopBuilder 系は Phase 186–187 で完全に削除済み。
|
|
|
|
|
|
ループに関する新しい要件はすべて JoinIR 側のパターン/箱の拡張で扱う。
|
|
|
|
|
|
- JoinIR の中に言語固有のハードコード(特定 Box 名や変数名)を戻すこと
|
|
|
|
|
|
- Trim/JsonParser 系は、構造(パターン)と補助箱(Promoter/Helper)で扱い、
|
|
|
|
|
|
「sum」「ch」など名前ベースの判定は LoopUpdateSummary / TrimLoopHelper の内部に閉じ込める。
|
|
|
|
|
|
|
|
|
|
|
|
この Roadmap は、JoinIR 層の変更や selfhost 深度を進めるたびに更新していくよ。
|