Files
hakorune/docs/development/current/main/design/joinir-plan-frag-ssot.md
tomoaki 630ed02c48 feat(joinir): Phase 286 P2.7 - V10不変条件追加(body_bb effects契約)
- verifier.rs: V10検証追加 - body_bbのblock_effectsは空でなければならない
  - 違反時: "[V10] Loop at depth N has non-empty block_effects for body_bb"
  - テスト: test_v10_body_bb_effects_in_block_effects_fails
- joinir-plan-frag-ssot.md: V10をPlan段階の不変条件に追加
- README.md: P2.7セクション追加

Phase 286 P2.6.1で発見した「lowererはloop_plan.bodyをemitし、
block_effectsのbody_bbは無視する」問題を契約化し再発防止。

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-26 04:55:14 +09:00

7.9 KiB
Raw Blame History

JoinIR Plan/Frag SSOT Documentation

Status: Active (2025-12-25) Phase: Phase 286 P0 (docs-only) Purpose: Single Source of Truth for Plan/Frag responsibilities, prohibitions, and freeze points


目標

JoinIR line を Plan/Frag に吸収する前提で、**責務・禁止事項・凍結点freeze points**をSSOTとして1ページに固定する。

「2本コンパイラ根治VM/LLVM」の合流点が明文化されていること。


1. Scope / Non-goals

対象Scope

  • JoinIR linePattern1-9における Plan → Frag → MIR merge の限定されたパイプライン
  • Plan と Frag の境界における責務分離
  • VM/LLVM 両コンパイラでの共通契約

対象外Non-goals

  • MIR実行・VM/LLVM固有の最適化
  • JoinIR外のloweringAST → MIR 全体ではなく、限定されたパイプラインのみ)

2. 用語Terms

用語 定義
JoinIR line (Pattern detection/Plan) → (Frag+Boundary) → (MIR merge) の限定されたパイプライン
Plan パターン抽出・正規化フェーズDomainPlan → CorePlan
Frag フラグメント生成・エミットフェーズJoinModule + JoinFragmentMeta
Boundary JoinInlineBoundaryhost↔JoinIR 変数マッピング)
ExitKind 継続の種類Return/Break/Continue/Kont
Freeze point 以降変更が禁止される確定ポイント
SSOT Single Source of Truth唯一の情報源

注記: JoinIR line は AST → MIR 全体ではなく、上記の限定された範囲を指すJoinIR外のloweringは含まない


3. 責務Responsibilities

Planが決めること

Plan 段階では以下を決定する:

  • パターン識別: どのパターンPattern1-9
  • 制御フロー構造: ループ/if/try/scan の構造
  • キャリア変数: ループ間で保持される変数
  • 継続構造: k_exit / k_continue の境界
  • ValueId 割り当て: JoinIRローカルのValueIdhost ValueId と衝突しない領域)

Planが決めないこと

Plan 段階では以下を決定しないFrag側の責務

  • ホスト変数: host inputs の ValueId はFrag側で決定
  • 最終的な命令列: Copy命令の注入はFrag側
  • PHI構造: header/exit PHIの最終構造はFrag側

Fragが保持すること

Frag 段階では以下を保持する:

  • JoinInlineBoundary: host↔JoinIR の全マッピング情報
  • JoinFragmentMeta: expr_result / exit_meta / continuation_funcs
  • terminator SSOT: emit_frag() を唯一のterminator生成ポイント

Fragが保持しないこと

Frag 段階では以下を保持しないPlan側の責務

  • パターン知識: Pattern1-9 の違いを知らないCorePlanのみ処理
  • AST情報: AST構造には直接アクセスしない

4. 禁止事項Prohibitions - 最重要)

禁止事項 理由
Planでの実行 Planは純粋なデータ構造
Planでの名前解決 名前解決はFrag側
Planでの最適化 Planは構造のみ記述
Planでのルール実装 ルールはFrag側で実装
Fragでのパターン識別 パターン知識はPlan側
明示的でないValueIdマッピング 全てBoundary経由
** terminator の多様な生成ポイント** emit_frag() SSOT
freeze point 以降の変更 不変条件違反

診断専用の扱い

開発中のデバッグ出力・トレースログは、debugタグ付き既定OFFでのみ許可。

実装注記ValueId領域

現状の実装では JoinIR-local ValueId として 100-999 領域を使用しているが、これは実装詳細であり変更されうる。SSOT としての原則は「host ValueId と衝突しない領域を使う」である。


5. 凍結点Freeze Points

Stage 凍結されるもの 以降禁止される操作
PlanFreeze (V1-V9) CorePlanの構造 Plan構造の変更
BoundaryFreeze JoinInlineBoundaryの全フィールド Boundaryマッピングの変更
ValueIdAllocate JoinIRローカルValueIdhostと非衝突領域 領域の再割り当て
MergeComplete MIR block構造 CFGの変更

6. 不変条件Invariants / Fail-Fast

Plan段階の不変条件

  • V1: 条件のValueIdは有効pre-generated
  • V2: Exitの妥当性Returnは関数内、Break/Continueはループ内
  • V3: Seqは非空
  • V4: Ifのthen_plansは非空
  • V5: ループはキャリアを1つ以上持つ
  • V6: Frag entryはheader_bbを指す
  • V7: block_effectsにheader_bbが含まれる
  • V10: body_bbのeffectsはloop_plan.bodyに積むblock_effects[body_bb]は空でなければならない)
    • Phase 286 P2.7 追加: lowererはloop_plan.bodyをbody_bbにemitし、block_effectsのbody_bbは無視する

Boundary段階の不変条件

  • B1: join_inputsのValueIdはhost ValueIdと衝突しない領域^1
    • JoinIR lowering では alloc_join_param() を使用すること(再発防止)
  • B2: exit_bindingsは対応するexit PHIを持つ
  • C1: 同じjoin_valueは同じhost_valueにマッピング
  • C2: condition bindingのjoin_valueはhost ValueIdと衝突しない領域^1
    • ConditionEnv 経由で割り当てられる

^1) 現状の実装では 100-999 の範囲を使用しているが、これは実装詳細であり将来の実装では変わりうる。

Merge段階の不変条件debug_assertions

  • M1: Header PHI dstは再定義されない
  • M2: Exit PHI inputsは全て定義されている
  • M3: terminator targetsは全て存在する
  • M4: ValueIdは領域を守っている

破ったらどこで落とすか

  • Contract違反: contract_checks.rs で早期return
  • Debug assert: debug_assert! / unreachable! で即座に落とす
  • 検証漏れ: CIで cfg(debug_assertions) テストを実行

7. 2本コンパイラ根治の合流点

共通パスShared Path

AST → JoinIR Plan → JoinIR Frag → MIR Merge

共通パスでは以下が共有される:

  • Pattern Detection: 同じパターン認識アルゴリズム
  • Boundary Construction: 同じ JoinInlineBoundary 構造
  • MIR Merge: 同じ merge_joinir_mir_blocks() ロジック

分岐点Divergence Point

MIR → [VM: MirInterpreter]
    → [LLVM: llvmlite/inkwell]

差分が許される場所

  • Method ID injection: LLVM側のみ
  • Experimental features: NYASH_JOINIR_VM_BRIDGE vs NYASH_JOINIR_LLVM_EXPERIMENT
  • Execution engines: MirInterpreter vs llvmlite

差分が許されない場所

  • JoinIR structure: 同じ構造でなければならない
  • PHI nodes: 同じPHI構造でなければならない
  • ValueId mappings: 同じマッピングでなければならない

8. デバッグ導線

詳細は CLAUDE.md へのリンク(重複させない):

  • NYASH_CLI_VERBOSE=1: 一般的な詳細ログ
  • HAKO_JOINIR_DEBUG=1: JoinIR ルーティング・ブロック割り当て
  • NYASH_TRACE_VARMAP=1: variable_map トレースPHI接続デバッグ
  • JoinIR architecture: docs/development/current/main/joinir-architecture-overview.md

関連ドキュメント


変更ログ

  • 2025-12-26: Phase 286 P2.7 - V10追加body_bb effects契約の明文化
  • 2025-12-25: Phase 286 P0 - 初版作成docs-only