Files
hakorune/docs/development/current/main/phases/phase-282

Phase 282: Router Shrinkage (pattern番号の症状ラベル化)

Status: Active SSOT / P0P9a complete (2025-12-23)

Goal:

  • pattern番号Pattern1/2/…)を “症状ラベル(テスト名)” に縮退させ、router の責務を「抽出の配線」へ収束させる。
  • CFG 構築は Frag/ExitKind 合成 SSOTcompose::* + emit_frag())へ一本化する。

SSOT References

  • Frag/emit SSOT: docs/development/current/main/design/edgecfg-fragments.md
  • Composition SSOT: src/mir/builder/control_flow/edgecfg/api/compose/mod.rs
  • JoinIR overview: docs/development/current/main/joinir-architecture-overview.md
  • Plan linePattern6/7: docs/development/current/main/phases/phase-273/README.md
  • Composition adoptionPattern6/7: docs/development/current/main/phases/phase-281/README.md

Problem

pattern番号が router の分岐点として肥大化すると、以下が起きる:

  • “認識extract” と “CFG構築lower” が混ざる
  • 分岐の追加が雪だるま式に増える実質、2つ以上のコンパイラを育てる
  • 収束先SSOTが曖昧になり、バグ修正の導線が折れる

Target Shape (SSOT)

router の役割をここまで縮退させる:

  • やる: Extractor の列挙、Ok(None)/Err の境界管理、Plan/JoinIR の入口選択
  • やらない: CFG構築のディテール、terminator 生成、推測 fallback

CFG構築は以下に収束させる

  • Plan line: Extractor → DomainPlan → Normalizer → CorePlan → Lowerer → emit_frag()
  • JoinIR line: cf_loop → (必要な抽出) → Frag composition → emit_frag()

P0 (docs-only) — SSOT 固定

  • router の責務/禁止事項を明文化by-name hardcode禁止、silent fallback禁止
  • "pattern番号の意味" を SSOT として定義(テスト名/症状ラベル)
  • 入口リンクを 10-Now.md に固定

Router Responsibilities SSOT

Router がやること:

  1. Extraction 戦略の列挙Plan-based, JoinIR table-based
  2. Extractor を優先順で呼び出しPlan line → JoinIR table
  3. Ok(None)/Err の境界管理Fail-Fast原則
  4. Entrypoint の選択Plan line vs JoinIR line
  5. Routing 決定のログ出力debug mode のみ、既存 trace 機構)

Router がやらないこと(禁止事項):

  1. CFG 構築block 割り当て、PHI 挿入、terminator 生成)
  2. Pattern 固有の lowering ロジックNormalizer/Lowerer に委譲)
  3. Silent fallbackエラーは明示的に
  4. By-name hardcode関数名マッチング禁止、debug 以外)
  5. Mock path fallbacktest 専用パターンの本番使用禁止)

Pattern 番号 = 症状ラベルPhase 280 SSOT positioning:

  • 正しい用途: テスト名(loop_if_phi.hako → Pattern3_WithIfPhi、debug ログ
  • 禁止: CFG 分岐(if pattern == 6 then ...)、アーキテクチャ SSOTFrag composition が SSOT

Detection 戦略Phase 282 P3-P7 migration 完了):

  • ExtractionBased (全Pattern統一): extract_*() 成功 → matchSSOT 単一)
    • Pattern1-5: Phase 282 P3-P7 で ExtractionBased 移行完了
    • Pattern6/7: Phase 273 Plan-based (extract_*_plan)
    • Pattern8/9: Phase 259/270 で既に ExtractionBased
    • pattern_kind: safety valve のみO(1) perf guard、検出ロジックではない

Pattern Detection SSOT Table (Phase 282 P3-P7 Complete)

全Pattern統一ルール:

  1. SSOT = extract: Extraction 関数が検出の唯一の真実pattern_kind ではない)
  2. Safety valve: pattern_kind は O(1) 早期reject のみ(検出ロジックに使わない)
  3. Re-extract: lower() は必ず再extract して SSOT 強制can_lower 通過を信じない)
Pattern SSOT Entrypoint Safety Valve Re-extract Phase
Pattern1 extractors/pattern1.rs::extract_* pattern_kind==Minimal P282 P3
Pattern2 extractors/pattern2.rs::extract_* pattern_kind==Basic P282 P4
Pattern3 extractors/pattern3.rs::extract_* pattern_kind==WithIfPhi P282 P5
Pattern4 extractors/pattern4.rs::extract_* pattern_kind==Carrier P282 P6
Pattern5 extractors/pattern5.rs::extract_* pattern_kind==InfiniteEarlyExit P282 P7
Pattern6 pattern6_scan_with_init.rs::extract_scan_with_init_plan() (none, Plan-based) P273 P1
Pattern7 pattern7_split_scan.rs::extract_split_scan_plan() (none, Plan-based) P273 P2
Pattern8 pattern8_scan_bool_predicate.rs (can_lower) (none, ExtractionBased) P259
Pattern9 pattern9_accum_const_loop.rs (can_lower) (none, ExtractionBased) P270

pattern_kind の正しい使い方:

  • O(1) guard: if pattern_kind != Expected { return false } (perf最適化)
  • Debug logging: pattern_kind={:?} (診断情報)
  • 検出ロジック: if pattern_kind == X then lower_X() (禁止、SSOT違反)
  • CFG 分岐: match pattern_kind { ... } (禁止、extract が SSOT)

移行完了状態 (Phase 282 P8):

  • すべての Pattern が extract_*() を SSOT として使用
  • pattern_kind は早期reject の補助にすぎない
  • lower() は必ず re-extract して SSOT 強制(二重検証)

SSOT 参照:

  • Frag composition: src/mir/builder/control_flow/edgecfg/api/compose/mod.rs
  • Plan line: src/mir/builder/control_flow/plan/normalizer.rs
  • Terminator 生成: emit_frag() (Phase 267)

Ok(None)/Err Boundary Rules

Fail-Fast 原則:

  • Ok(None): Extraction がパターンに一致しなかった(次を試す)
  • Err(String): Extraction が一致したが検証失敗(即座に fail
  • 禁止: Close-but-unsupported → Ok(None)Err で返すべき)

:

// ✅ 正しい: 一致しない
extract_scan_with_init_plan()  Ok(None)  // 次のパターンを試す

// ✅ 正しい: 一致したが非サポート
extract_scan_with_init_plan()  Err("P1 scope: reverse scan not supported")

// ❌ 禁止: Silent fallback
extract_scan_with_init_plan()  Ok(None) for unsupported cases
// (非サポートケースを Ok(None) で返してはいけない)

境界の位置router.rs 実装):

  • Plan linelines 310-337, 341-368: extract → match → Normalize → Verify → Lower
  • JoinIR tablelines 376-382: can_lower → lower
  • No matchlines 384-395: Ok(None) を caller に返すErr ではない)

Entrypoint Table

Entrypoint Entry Condition Patterns SSOT Downstream
Plan line extract_*_plan() が Ok(Some) Pattern6/7 Normalizer → CorePlan → Lowerer → emit_frag
JoinIR table LOOP_PATTERNS 反復 Pattern1-5,8-9 cf_loop 抽出 → Frag composition → emit_frag
No match すべての extract が Ok(None) (none) Err を caller に返す

Plan line の責務Phase 273 SSOT:

  1. Extraction: extract_*_plan()pure、builder 不要)
  2. Normalization: PlanNormalizerpattern 知識の展開)
  3. Verification: PlanVerifierfail-fast 検証)
  4. Lowering: PlanLowererblock/value 割り当て + Frag composition
  5. Emission: emit_frag()terminator SSOT

JoinIR table の責務Phase 194+ table-driven:

  1. Detection: can_lower()pattern により structure-based / extraction-based が混在)
  2. Extraction: cf_loop 抽出
  3. 収束先: Frag composition → emit_frag内部パイプライン詳細は最小化

収束先の統一Phase 282 Goal:

  • すべての entrypoint が最終的に emit_frag() に収束terminator 生成の SSOT
  • CFG 構築の詳細は router が持たない(抽出の配線のみ)

P1 (code, minimal) — 配線の可視化

Follow-up (design-first): Return as ExitKind SSOT

移行期間中に一番 “ズレやすい” のは return まわりなので、pattern 個別実装へ散らさず、 ExitKind + compose::* / emit_frag() に収束させる方針を別フェーズで扱う。

  • 入口: docs/development/current/main/30-Backlog.mdPhase 284

P9a (refactor, behavior-preserving) — Extractor 重複削減Common helpers

Pattern15 の extractor が持っていた “再帰カウント/検出/条件ヘルパ” の重複を、pure helper に集約する。

  • 追加: src/mir/builder/control_flow/joinir/patterns/extractors/common_helpers.rs

  • 方針:

    • SSOT=extract は維持(判定は各 pattern extractor の責務)
    • helper は purebuilder 触らない)・silent fallback を作らない
    • Pattern3 の “if-else PHI” は専用ロジックが多いため、段階的に扱うP9b 以降)
  • router に “経路ログ” を追加既定OFF、debugのみに限定

  • pattern番号ではなく “entrypointPlan/JoinIR” をログの主語にする

Acceptance (Phase 282)

  • router の責務が docs で SSOT 化されている
  • router の変更が「extractor配線」のみになっているCFG構築の詳細を持たない
  • 既存の VM/LLVM smokes に退行がない