Files
hakorune/docs/development/current/main/design/joinir-design-map.md
nyash-codex 93e62b1433 docs(phase93): Phase 93 P0完了記録 & ドキュメント整理
## 追加
- docs/development/current/main/phases/phase-93/README.md
  - Phase 93 P0 (ConditionOnly Derived Slot) 完了記録
  - 実装内容・テスト結果の詳細

## 更新
- CURRENT_TASK.md: Phase 93 P0完了に伴う更新
- 10-Now.md: 現在の進捗状況更新
- 30-Backlog.md: Phase 92/93関連タスク整理
- phase-91/92関連ドキュメント: historical化・要約化

## 削減
- 735行削減(historical化により詳細をREADMEに集約)

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

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-16 23:30:39 +09:00

13 KiB
Raw Blame History

JoinIR Design Map現役の地図

Status: SSOTnavigation
Scope: JoinIR の「Loop/If を JoinIR 化して MIR に統合する」導線検出→shape guard→lower→merge→契約検証
Related:

このドキュメントは Phase ログではなく、「JoinIR を触る人が迷子にならず、どこを直すべきかが一発で分かる」ための設計図(地図)です。
詳細な経緯・作業ログは docs/development/current/main/phases/docs/development/current/main/investigations/ に分離します。

役割分担joinir-architecture-overview との分離)

このファイルは「実装導線の地図」の SSOT ですnavigation SSOT
意味論・契約・不変条件の本文normativedocs/development/current/main/joinir-architecture-overview.md を SSOT とします。

使い分け:

  • 「JoinIR が何を保証し、何を Fail-Fast で落とすべきか」→ joinir-architecture-overview.md
  • 「どのファイルを触るべきか」「入口はどこか」「追加手順は?」→ この joinir-design-map.md
  • 「経緯/ログ/切り分け」→ docs/development/current/main/phases/docs/development/current/main/investigations/

1枚図: レイヤーAST → JoinIR → MIR → Backend

flowchart LR
  A[AST] -->|Frontend lowering| J1[JoinIR (Structured)]
  J1 -->|Normalize / Shape guard| J2[JoinIR (Normalized)]
  J2 -->|JoinIR → MIR bridge| M1[MIR Module]
  M1 -->|Merge into host function| M2[MIR (in builder)]
  M2 --> B[Backend\n(VM / LLVM / Cranelift)]

  subgraph Frontend
    A
    J1
  end

  subgraph JoinIR Core
    J2
  end

  subgraph MIR Builder
    M1
    M2
  end

読み方:

  • 「Loop/If の形が認識されない」: Pattern 検出Feature/Kindと shape guard を見る
  • 「JoinIR は生成できるが統合で壊れる」: MergeValueId/PHI/ExitLine/Boundaryと契約検証を見る
  • 「なぜこのエラータグが出たか」: ErrorTagsSSOTを起点に呼び出し元へ辿る

“箱”の責務マップ(担当境界)

領域 役割(何を決めるか) 主な入口/箱SSOT寄り 主な出力 Fail-Fast典型
Pattern検出 ループ形を分類し、どの lowerer に渡すか決める src/mir/builder/control_flow/joinir/patterns/router.rs, src/mir/builder/control_flow/joinir/patterns/ast_feature_extractor.rs, src/mir/loop_pattern_detection/mod.rs LoopPatternKind / Pattern 選択 「分類不能」→ 明示的に Errサイレントな非JoinIR退避は禁止
shape guard 「この shape なら lower/merge 契約が成立する」を保証する src/mir/join_ir/normalized/shape_guard.rs, src/mir/builder/control_flow/joinir/patterns/*_validator.rs shape OK / 詳細診断 shape 不一致を握りつぶさず Err
lowering JoinIRStructured/Normalizedを生成する src/mir/join_ir/lowering/mod.rs, src/mir/builder/control_flow/joinir/patterns/pattern*_*.rs JoinModule 未対応の構造は error_tags::freeze(...) 等で Err
merge JoinIR→MIR 変換後、ホスト関数に統合する src/mir/builder/control_flow/joinir/patterns/conversion_pipeline.rs, src/mir/builder/control_flow/joinir/merge/mod.rs ホスト MIR のブロック/ValueId 更新 ValueId 競合、ExitLine 未接続、PHI 破綻を Err
ExitMeta 「出口でどの carrier をどの host slot に戻すか」のメタ src/mir/join_ir/lowering/carrier_info.rs, src/mir/builder/control_flow/joinir/merge/exit_line/meta_collector.rs ExitMeta / exit_bindings carrier 不整合(不足/過剰)を Err
CarrierInit carrier 初期化の SSOTFromHost/Const/LoopLocal src/mir/builder/control_flow/joinir/merge/carrier_init_builder.rs, src/mir/join_ir/lowering/carrier_info.rs 初期値 ValueId 初期化経路の分岐が散らばらないSSOT を使う)
ErrorTags エラータグ整形の SSOT検索性・一貫性 src/mir/join_ir/lowering/error_tags.rs 文字列タグ 文字列ハードコードを避け、タグを一元化

注:

  • Pattern 検出は「関数名 by-name 分岐」に依存しない(構造で決める)。必要なら dev/診断限定のガードに閉じ込める。
  • shape guard は「OK なら後工程が前提にできる契約」を固定する場所で、曖昧な許容をしない。

入口(コード側のエントリポイント)

Loopbuilder 側の導線)

JoinIRIR/正規化/ブリッジ)

共通(診断とタグ)


不変条件Fail-Fast

JoinIR を触るときは、次を破ったら「即エラーで止める」前提で設計・実装する。

形状shape

  • Pattern は「認識できる shape だけ」を通し、曖昧な許容をしない。
  • 形状が合わないときは Ok(None) で静かに進めない非JoinIRへの退避を作らない
    • 例外: 明確な “routing” で「別 JoinIR 経路」を選ぶのは可(同一層内での選択)。

ValueId / PHI / Boundary の世界

  • JoinIR 内部JoinValueSpace 等)と host MIR builder の ValueId を混ぜない。
  • Boundary は JoinIR↔host の橋渡し契約:
    • join_inputshost_inputs の対応が明示される
    • Exit 側は “carrier 名” をキーにして reconnection されるExitMeta/exit_bindings
  • PHI は「誰が確保するか」を固定し、衝突を許さないPHI dst の予約・再利用禁止)。

ExitLine 契約

  • ExitLine は「出口へ集約する」ための契約であり、未接続の経路を残さない。
  • carrier/slot の不足・余剰・不整合は error_tags::exit_line_contract(...) 等で即エラーにする。

Allocator SSOTPhase 135

  • 原則: すべての ValueId 発行は単一の allocatorConditionContext.alloc_value)を経由する
  • 禁止事項: ConditionLoweringBox / ExprLowerer での内部カウンタ使用
  • 理由: JoinIR params (ValueId(1000+)) と衝突し、merge 時に header PHI dst を上書きする
  • 検出: --verify で "Value %N defined multiple times" エラー
  • 修正例: Phase 135 P0 - ConditionLoweringBox が &mut ConditionContext を受け取り、alloc_value を必ず使用

Boundary Injection SSAPhase 135

  • 原則: condition_bindings は alias を許すが、注入 Copy の dst は重複させない
  • Fail-Fast: 異なる source が同一 dst に来る場合は即座にエラー
  • 理由: MIR SSA を破壊し、VM/LLVM で未定義動作を引き起こす
  • 検出: joinir_inline_boundary_injector.rs の重複排除ロジック
  • 修正例: Phase 135 P0 - Boundary Copy deduplication by dst

Box 実装チェックリスト

Box を新規実装・変更した際は以下を必ず確認:

  1. --verify で契約違反が検出されるかSSA 破綻・ValueId 衝突)
  2. smoke test で退行が出ないかphase132/133/135 など)
  3. allocator を bypass していないかConditionContext.alloc_value を使っているか)
  4. boundary injection で dst 重複を防いでいるか

追加手順チェックリスト(新しいループ形を飲み込む最小手順)

「新しいループ形」を JoinIR で扱えるようにするときの最小手順。

  1. Fixture を追加(再現可能に固定)
    • apps/tests/ または apps/smokes/ に最小の .hako を追加(対象形が一目で分かるもの)
  2. Pattern/feature を追加(検出)
    • src/mir/builder/control_flow/joinir/patterns/ast_feature_extractor.rs(必要なら feature 抽出を拡張)
    • src/mir/loop_pattern_detection/(分類/補助解析が必要ならここに追加)
  3. shape guard を追加(契約の固定)
    • 形状・前提条件を validator として分離し、失敗は Err にする
  4. lower を追加JoinIR を生成)
    • 既存 pattern のコピーではなく、「今回の shape が要求する最小構成」にする
    • エラーは src/mir/join_ir/lowering/error_tags.rs を使いタグを固定する
  5. merge/ExitLine を接続(契約が満たされるように)
    • carrier/ExitMeta/Boundary が揃っているか確認する
  6. Tests を追加(仕様固定)
    • unit: pattern/validator/merge の局所テスト
    • smoke: tools/smokes/v2/ の profile に軽いケースを追加quick を重くしない)
  7. Docs を更新(地図を更新)
    • docs/development/current/main/loop_pattern_space.md(パターン空間に追記が必要なら)
    • docs/development/current/main/joinir-architecture-overview.md(箱/契約が増えたなら)
    • 本ファイル(入口・責務マップの更新)