Files
hakorune/docs/development/current/main/phases/phase-260
tomoaki fc6eed1b04 docs: Phase 260 P2 完了記録 + EdgeCFG SSOT 確立
Update phase-260/README.md:
- Status: P2 完了 (EdgeCFG SSOT確立)
- Add P2 completion record with test results
- Add EdgeCFG SSOT definition (Jump/Branch: terminator SSOT, Return: metadata exception)
- Document unified API (read/write separation)
- Note Option B' trade-off (Return metadata exception)

Update 10-Now.md:
- Add Phase 260 P2 completion entry (2025-12-21)
- Test results: 1368 lib tests, 45/46 smoke, phase258 tail call
- Verification: 0 jump_args references (comments excluded)
- 9 files modified

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

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

Phase 260: Block-Parameterized CFGedge-args段階導入

Status: P2 完了 EdgeCFG SSOT確立 Last updated: 2025-12-21

進捗(セーブポイント)

  • P0併存導入の芯: 完了(読む側 SSOT を out_edges()/edge_args_to() に寄せた)
    • Commit: 4dfe3349b
  • P0.1hardening: 完了legacy layout 無し禁止 + DCE/verify の参照点整理)
    • Commit: 1fe5be347
  • P0.2instruction_rewriter モジュール化): 完了
    • Commits: cbed040a7, aa3fdf3c1, c2e8099ff, 84cd653ae, 875bfee1b, 666de9d3e
    • 抽出モジュール: exit_collection, block_allocator, merge_variable_handler, call_generator, handlers/8ファイル
  • P0.3joinir_block_converter モジュール化): 完了
    • Commits: e7f9adcfe, 2c01a7335
    • Phase 1: terminator_builder, block_finalizer
    • Phase 2: handlers/call, jump, conditional_method_call, if_merge, nested_if_merge
    • 合計抽出: 15モジュール、約3941行、53単体テスト全てpass
    • 統合テスト: 45/46 pass既知のPattern2 LoopBodyLocal問題1件のみ
  • P2削除: 完了
    • BasicBlock.jump_args 完全削除、edge-args SSOT を terminator operand 側に一本化
    • フィールド変更: jump_argsreturn_envReturn専用metadata
    • API簡略化: legacy helper 8個削除、terminator更新API保持successors同期維持
    • Verification簡素化: dual-source検証削除cfg.rs 62行削除
    • テスト結果: cargo test --lib 1368 PASS、quick smoke 45/46 PASS、phase258 tail call PASS
    • 検証: rg 'jump_args' src/ = 0件コメント除く

P0.2/P0.3 モジュール分割の責務一覧

Utilities7モジュール

  • block_allocator.rs: ブロックID割り当て統一allocate_one/two/three/n
  • merge_variable_handler.rs: マージコピー生成emit_merge_copies, MergeBranch
  • call_generator.rs: Call命令生成統一emit_call_pair, emit_call_pair_with_spans
  • terminator_builder.rs: Terminator生成統一create_branch/jump/return_terminator, emit_branch_and_finalize
  • block_finalizer.rs: PHI保持ブロック確定finalize_block, finalize_remaining_instructions
  • exit_collection.rs: Exit値収集collect_exit_values, ExitCollectionResult
  • convert.rs: MirLikeInst変換convert_mir_like_inst

Handlers8モジュール

  • handlers/ret.rs: Return処理
  • handlers/method_call.rs: MethodCall → BoxCall変換
  • handlers/field_access.rs: FieldAccess → BoxCallgetter pattern
  • handlers/new_box.rs: NewBox命令処理
  • handlers/select.rs: Select命令直接、展開なし
  • handlers/call.rs: Call + tail call処理Phase 131 P2: 安定ValueId、legacy jump_args
  • handlers/jump.rs: Jump → tail call変換Phase 256 P1.9: continuation、Phase 246-EX: legacy jump_args
  • handlers/conditional_method_call.rs: ConditionalMethodCall → if/phi展開単一変数
  • handlers/if_merge.rs: IfMerge → if/phi複数変数
  • handlers/nested_if_merge.rs: NestedIfMerge → 多段分岐N+3ブロック、最複雑

SSOT維持の確認項目Phase 260の契約

jump_args直参照ゼロ維持: 全モジュールでBasicBlock.jump_argsへの直接参照なし(out_edges()/edge_args_to()経由のみ) out_edges()/edge_args_to() SSOT維持: 読む側APIが単一参照点に統一Branchを含む複数edge前提 terminator operand優先: 新規コードはterminator operandを優先的に使用legacy jump_argsは併存のみ PHI preservation: block_finalizer.rsでPhase 189 FIXPHI命令をブロック先頭保持を維持 Phase metadata保持: Phase 131 P2安定ValueId、Phase 246-EXlegacy jump_args、Phase 256 P1.9continuation名前解決の契約を全て保持

EdgeCFG SSOT確立P2完了後

Edge-args の SSOT定義:

  • Jump/Branch: terminator operand edge_args が SSOT
  • Return: metadata return_env が SSOT例外、terminator に operand フィールドなし)⚠️

統一API:

  • 読み出し: out_edges(), edge_args_to(), edge_args_from_terminator()
  • 書き込み: set_jump_with_edge_args(), set_branch_with_edge_args(), set_return_env()
    • 直代入禁止successors 同期漏れ防止、Phase 260/261の核心成果

妥協点の明記:

  • Returnは「CFG successorを持たない」semantic上の特殊ケースのため、metadata許容
  • 理想形Option AはReturn terminatorにenvフィールド追加だが、P2では工数削減のためOption B'採用

目的P0

JoinIR→MIR の暗黙 ABIjump_args / carriers / expr_result slot / successorsを減らし、将来的な block-parameterized CFGedge-args を第一級に持つCFGへ収束するための「大工事パート」を開始する。

このフェーズは “一括置換” ではなく、**併存導入Strangler**で可逆に進める。

背景Phase 256-259 で露出した型)

  • jump_args が IR 外メタとして存在すると、DCE/verify/CFG 更新が「忘れると壊れる」になる
  • spans が並行 Vec だと、最適化や変換で同期漏れが起きやすい
  • continuation / entry / exit の識別と args 順序が散在すると、推測・補正が増殖する

North Star: docs/development/current/main/design/join-explicit-cfg-construction.md

方針2段正規化

  • Semantic Normalization意味SSOT: terminator 語彙の固定(例: cond付きJumpを正規形から禁止しBranchへ
  • Plumbing Normalization配線SSOT: edge-args / CFG successor / spans を IR 構造に閉じ込め、写像に縮退

スコープPhase 260

In scope

  • MIR に「edge-args を持つ terminator 表現」を 併存導入する(旧 BasicBlock.jump_args は残す)
  • “読む側” を単一APIに寄せるBranch を含むので “複数 edge” 前提で一本化する)
    • 例: block.out_edges() / block.edge_args_to(target)
  • 互換期間は 一致検証を Fail-Fast(両方ある場合は矛盾で即死)

Out of scopeP0ではやらない

  • BasicBlock.jump_args の削除(削除は Phase 261+
  • spans の内部表現を Vec<Spanned<_>> に一気に切替Phase 261+ で段階導入)
  • JoinIR を削除するbuilder DSL 降格は長期)

実装タスクP0

  1. MirTerminator(または既存 terminator に edge-args を持てる variantを追加併存導入
    • Jump だけでなく Branch を含むため、API は “複数 edge” を前提にする
  2. bridge が Jump/Branch の edge-args を terminator operand としてもセット旧jump_argsも併記してよい
  3. merge/ExitLine/DCE/verify/printer が参照する入口を一本化(読む側の Strangler
    • 推奨: block.out_edges() / block.edge_args_to(target) のような APIedge_args() 単発は Branch で曖昧)
  4. Fail-Fast 契約チェック(--verify 時に必須)
    • “両方ある場合は一致” を verify で保証
    • 追加: “terminator から計算した successors” と “block.successors キャッシュ” の一致も verify で保証(同期漏れを即死)

受け入れ基準P0

  • cargo build --release が通る
  • ./tools/smokes/v2/run.sh --profile quick が少なくとも悪化しないsame first FAIL 以上)
  • --verify の既存テストが壊れないPHI/CFG検証が健全
  • legacy 依存の “推測” が増えていない(新規の env var 追加なし)
  • rg "jump_args" を走らせて、移行コードと API 以外に参照が増えていない(読む側の寄せ漏れを検出)
  • DCE 回帰が 1 本以上あり、「edge-args だけで使われる値」が消されないことを固定できている

ロードマップP0→P3

P0併存導入の芯

  • 単一参照APIを作るBranch を含むので “複数 edge” 前提)
    • 例: BasicBlock::out_edges() / BasicBlock::edge_args_to(target)
  • MIR terminator に edge-args を持てる表現を追加(旧 jump_args併存
    • 推奨: EdgeArgs { layout: JumpArgsLayout, values: Vec<ValueId> } のように “意味layout” も同梱する
  • bridge が edge-args を terminator operand に必ず埋める旧jump_argsも同内容でセットしてよい
  • merge/ExitLine/DCE/verify/printer は参照点を out_edges()/edge_args_to(...) に寄せる
  • 両方ある場合の 一致検証を Fail-Fast--verify で必須)

P1切替

  • jump_args を読む経路を段階的に減らす(参照点は out_edges()/edge_args_to(...) のみ)
  • terminator 更新の API一本化successors/preds の同期漏れを構造で潰す)
    • 読む側だけでなく、書く側terminator 設定/edge-args 設定)も API 経由に寄せる
  • DCE/verify が terminator operand から自然に use/pred を追えることを固定する

P2削除

  • BasicBlock.jump_args を削除(併存チェックも撤去)
  • jump_args 特例の DCE/verify コードを削除terminator operand が SSOT

P3spans 収束)

  • instructions + instruction_spans の並行 Vec を段階導入で廃止
    • 先に編集APIを一本化 → 最終的に Vec<Spanned<MirInstruction>>

メモ設計SSOT

  • 相談パケット: docs/development/current/main/investigations/phase-259-block-parameterized-cfg-consult.md
  • decisions: docs/development/current/main/20-Decisions.md