Files
hakorune/docs/development/current/main/phase69-4.3-trio-to-loopscope-migration.md
nyash-codex ea120dc9b1 docs(phi_core): Phase 69-4 完全達成!Trio 削除準備完了
## 変更内容

### docs/development/current/main/phase69-4-trio-deletion-plan.md
- Phase 69-4.3: json_v0_bridge Trio 依存設計完了記録
  - 二重分類問題発見(変数分類が2回実行されている無駄)
  - Gap ゼロ確認(LoopScopeShape が Trio 完全カバー)
  - 最小変更設計(14行→2行、85%削減)
- Phase 69-4.4: Trio 削除条件固定完了記録
  - 6ステップ削除手順確定(合計3時間見積もり)
  - 安全性保証(退行防止策・ロールバック計画)
  - 削除完了条件(5項目の明確な基準)
- Phase 69-4.5: Phase 70 橋渡し完了記録
  - 実装パッケージ完備(設計・手順・Checklist)
  - Phase 70 開始条件すべて満たした
- まとめセクション更新
  - Phase 69-4 完全達成宣言
  - Phase 69 合計削減見込み ~1,485行
  - Phase 48-6 設計の完全勝利(進化の歴史)

## Phase 69-4 完了サマリー

### 達成タスク(5/5完了)
-  69-4.1: Trio callsite 棚卸し(Task agent)
-  69-4.2: phi_core 公開面削減方針明文化
-  69-4.3: json_v0_bridge Trio 依存設計
-  69-4.4: Trio 削除条件固定
-  69-4.5: Phase 70 橋渡し

### 成果物
- 📄 全体計画: phase69-4-trio-deletion-plan.md (完成)
- 📄 詳細設計: phase69-4.3-trio-to-loopscope-migration.md (20KB)
- 📋 TODO マーカー: src/mir/phi_core/mod.rs (L33-40)

### 削減見込み
- **~1,443行**(Trio 3箱 + 使用箇所)
  - 定義ファイル: 1,353行
  - loop_form_intake.rs: 14行 → 2行(12行削減)
  - loop_snapshot_merge.rs: ~60行削減
  - 呼び出し側: ~18行削減

### Phase 70 実装準備
-  6ステップ削除手順確定
-  Before/After コード例完備
-  3段階ロールバック計画
-  Checklist コピペ用完備

## 重要な発見

### 1. 二重分類問題
現在、変数分類が2回実行されている無駄を発見:
- intake_loop_form() で分類 ← 削除対象
- LoopScopeShape::from_loop_form() で再度分類 ← 正解

### 2. Gap ゼロ
LoopScopeShape は Trio 全機能をカバー済み:
- LocalScopeInspectorBox → variable_definitions 
- LoopVarClassBox → classify_all() 
- LoopExitLivenessBox → exit_live 

### 3. 最小変更
loop_form_intake.rs の 14行を 2行に削減可能(85%削減)

## Phase 48-6 設計の完全勝利

進化の軌跡:
1. Phase 25.1: Option C 実装(Trio 誕生)
2. Phase 48-4: LoopScopeShape 実装(Trio 代替)
3. Phase 48-6: Trio を builder.rs に封じ込め
4. Phase 69-3: MIR 決定性修正(BTreeSet 化)
5. **Phase 69-4: Trio 削除準備完了**
6. **Phase 70: Trio 完全削除**(予定)

設計哲学: 代替実装 → 可視性制御 → 設計固め → 安全削除

## 次のステップ

Phase 70 実装開始準備完了!
- 見積もり: 3時間
- 削減見込み: ~1,443行
- Checklist: phase69-4-trio-deletion-plan.md 参照

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-30 10:10:45 +09:00

19 KiB
Raw Blame History

Phase 69-4.3: Trio 依存を LoopScopeShape に寄せる設計

目的

loop_form_intake.rs の Trio (LoopVarClassBox, LoopExitLivenessBox, LocalScopeInspectorBox) 依存を LoopScopeShape に置き換える設計を策定し、Phase 70 での実装準備を整える。


1. 現状分析: loop_form_intake.rs での Trio 使用パターン

1.1 intake_loop_form() 関数の役割

intake_loop_form() は LoopForm と MIR から以下を抽出する「入口箱」:

pub(crate) struct LoopFormIntake {
    pub pinned_ordered: Vec<String>,
    pub carrier_ordered: Vec<String>,
    pub header_snapshot: BTreeMap<String, ValueId>,
    pub exit_snapshots: Vec<(BasicBlockId, BTreeMap<String, ValueId>)>,
    pub exit_preds: Vec<BasicBlockId>,
}

1.2 Trio の使用箇所L169-182

// LocalScopeInspector に snapshot を登録して VarClass 判定の土台を整える
let mut inspector = LocalScopeInspectorBox::new();
inspector.record_snapshot(loop_form.header, &header_vals_mir);
for (bb, snap) in &exit_snapshots {
    inspector.record_snapshot(*bb, snap);
}

let all_names: Vec<String> = header_vals_mir.keys().cloned().collect();
let classified = var_classes.classify_all(
    &all_names,
    &pinned_hint,
    &carrier_hint,
    &inspector,
    &exit_preds,
);

let ordered_pinned: Vec<String> = classified
    .iter()
    .filter(|(_, c)| matches!(c, LoopVarClass::Pinned))
    .map(|(n, _)| n.clone())
    .collect::<BTreeSet<_>>()
    .into_iter()
    .collect();
let ordered_carriers: Vec<String> = classified
    .iter()
    .filter(|(_, c)| matches!(c, LoopVarClass::Carrier))
    .map(|(n, _)| n.clone())
    .collect::<BTreeSet<_>>()
    .into_iter()
    .collect();

1.3 Trio 3箱の責務

  1. LocalScopeInspectorBox(変数定義追跡)

    • 役割: 各 basic block で定義されている変数を記録
    • 使用メソッド:
      • record_snapshot(block, vars): snapshot を登録
      • is_available_in_all(var, blocks): 全 block で利用可能か判定
      • get_defining_blocks(var): 定義されている block 一覧を取得
      • all_variables(): 全変数名を取得
  2. LoopVarClassBox(変数分類)

    • 役割: 変数を 4分類Pinned/Carrier/BodyLocalExit/BodyLocalInternal
    • 使用メソッド:
      • classify_all(vars, pinned_hint, carrier_hint, inspector, exit_preds): 一括分類
      • classify(var, ...): 単一変数分類
  3. LoopExitLivenessBoxexit 後 liveness

    • 役割: exit 後で使われる変数集合を計算
    • 使用メソッド:
      • compute_live_at_exit(query, exit_block, header_vals, exit_snapshots): live 変数集合を返す
    • 現状: 保守的近似(全変数を live とみなす)

2. LoopScopeShape カバー範囲

2.1 LoopScopeShape の構造

pub(crate) struct LoopScopeShape {
    pub header: BasicBlockId,
    pub body: BasicBlockId,
    pub latch: BasicBlockId,
    pub exit: BasicBlockId,
    pub pinned: BTreeSet<String>,
    pub carriers: BTreeSet<String>,
    pub body_locals: BTreeSet<String>,
    pub exit_live: BTreeSet<String>,
    pub progress_carrier: Option<String>,
    pub(crate) variable_definitions: BTreeMap<String, BTreeSet<BasicBlockId>>,
}

2.2 LoopScopeShape の提供 API

API 機能 Trio 対応
classify(var) 変数を 4分類 LoopVarClassBox.classify()
classify_all(vars) 一括分類 LoopVarClassBox.classify_all()
needs_header_phi(var) header PHI 必要性判定 LoopVarClass.needs_header_phi()
needs_exit_phi(var) exit PHI 必要性判定 LoopVarClass.needs_exit_phi()
get_exit_live() exit 後 live 変数集合 LoopExitLivenessBox.compute_live_at_exit()
is_available_in_all(var, blocks) 全 block で利用可能か LocalScopeInspectorBox.is_available_in_all()
pinned_ordered() 順序付き pinned 一覧 LoopFormIntake.pinned_ordered
carriers_ordered() 順序付き carrier 一覧 LoopFormIntake.carrier_ordered
header_phi_vars() header PHI 対象変数 pinned + carriers
exit_phi_vars() exit PHI 対象変数 exit_live

2.3 Phase 48-4 完了の成果

  • Trio の内部化: LoopScopeShape::from_existing_boxes_legacy() が Trio を使用
  • 外部からの隠蔽: 利用側は LoopScopeShape::from_loop_form() 経由で Trio を知らない
  • helper 関数の整備:
    • build_inspector(): LocalScopeInspectorBox 構築
    • classify_body_and_exit(): LoopVarClassBox による分類
    • merge_exit_live_from_box(): LoopExitLivenessBox による exit_live 計算
    • extract_variable_definitions(): variable_definitions 抽出

3. Gap 分析

3.1 カバーできている機能

機能 loop_form_intake.rs LoopScopeShape 状態
変数分類4分類 classify_all() classify() 完全カバー
pinned/carrier 判定 hint → classify BTreeSet 保持 完全カバー
exit_live 計算 未使用 get_exit_live() LoopScopeShape が優位
定義位置追跡 inspector variable_definitions 完全カバー
順序付き一覧 Vec 生成 *_ordered() API 完全カバー

3.2 カバーできていない機能

結論: なしLoopScopeShape は Trio の全機能をカバーしている。

3.3 loop_form_intake.rs 固有の役割

loop_form_intake.rs が提供している機能で LoopScopeShape が直接提供していないもの:

  1. MIR パース: preheader から変数名を推定L31-88

    • s (StringBox param), n (length), i (index) の抽出
    • value_to_name マッピング構築
  2. header φ 読み取り: header PHI から snapshot 構築L96-129

    • pinned/carrier の hint 生成
    • incoming values の追跡
  3. exit preds 収集: CFG から exit 前駆者を列挙L147-153

  4. LoopFormIntake 構造体: 抽出結果を整形して返す

重要な洞察:

  • これらは LoopForm → LoopScopeShape への変換ロジック であり、
  • LoopScopeShape::from_loop_form() が既に内部で実行している処理

4. 移行設計

4.1 現在の呼び出しフローBefore

// json_v0_bridge/lowering/loop_.rs仮想例
fn lower_loop_to_joinir(
    loop_form: &LoopForm,
    query: &impl MirQuery,
    mir_func: &MirFunction,
) -> Option<JoinIR> {
    // Step 1: Trio 箱を生成
    let var_classes = LoopVarClassBox::new();
    let exit_live_box = LoopExitLivenessBox::new();

    // Step 2: loop_form_intake を呼び出し
    let intake = intake_loop_form(
        loop_form,
        &var_classes,  // ← Trio 依存!
        query,
        mir_func,
    )?;

    // Step 3: LoopScopeShape を構築
    let scope = LoopScopeShape::from_existing_boxes(
        loop_form,
        &intake,
        &var_classes,      // ← Trio 依存!
        &exit_live_box,    // ← Trio 依存!
        query,
        func_name,
    )?;

    // Step 4: JoinIR lowering
    some_joinir_lowerer(&scope, ...)
}

4.2 Phase 70 後の呼び出しフローAfter

// json_v0_bridge/lowering/loop_.rsPhase 70版
fn lower_loop_to_joinir(
    loop_form: &LoopForm,
    query: &impl MirQuery,
    mir_func: &MirFunction,
) -> Option<JoinIR> {
    // Step 1: LoopFormIntake を生成Trio なし版)
    let intake = intake_loop_form_v2(
        loop_form,
        query,
        mir_func,
    )?;

    // Step 2: LoopScopeShape を構築Trio 内部化)
    let scope = LoopScopeShape::from_loop_form(
        loop_form,
        &intake,
        query,
        func_name,
    )?;

    // Step 3: JoinIR lowering変更なし
    some_joinir_lowerer(&scope, ...)
}

4.3 intake_loop_form() の書き換え(核心部分)

BeforeL169-182

// LocalScopeInspector に snapshot を登録して VarClass 判定の土台を整える
let mut inspector = LocalScopeInspectorBox::new();
inspector.record_snapshot(loop_form.header, &header_vals_mir);
for (bb, snap) in &exit_snapshots {
    inspector.record_snapshot(*bb, snap);
}

let all_names: Vec<String> = header_vals_mir.keys().cloned().collect();
let classified = var_classes.classify_all(
    &all_names,
    &pinned_hint,
    &carrier_hint,
    &inspector,
    &exit_preds,
);

let ordered_pinned: Vec<String> = classified
    .iter()
    .filter(|(_, c)| matches!(c, LoopVarClass::Pinned))
    .map(|(n, _)| n.clone())
    .collect::<BTreeSet<_>>()
    .into_iter()
    .collect();
let ordered_carriers: Vec<String> = classified
    .iter()
    .filter(|(_, c)| matches!(c, LoopVarClass::Carrier))
    .map(|(n, _)| n.clone())
    .collect::<BTreeSet<_>>()
    .into_iter()
    .collect();

AfterPhase 70 版)

// Phase 70: Trio 分類を削除し、pinned_hint/carrier_hint をそのまま返す
// 実際の分類は LoopScopeShape::from_loop_form() 内部で実施される

let ordered_pinned: Vec<String> = pinned_hint.into_iter().collect::<BTreeSet<_>>().into_iter().collect();
let ordered_carriers: Vec<String> = carrier_hint.into_iter().collect::<BTreeSet<_>>().into_iter().collect();

削減効果:

  • L169-182 の 14行を 2行に削減 → 85% 削減!
  • Trio 依存を完全排除
  • ロジック重複を解消LoopScopeShape が SSOT に)

4.4 関数シグネチャの変更

Before

pub(crate) fn intake_loop_form(
    loop_form: &crate::mir::loop_form::LoopForm,
    var_classes: &LoopVarClassBox,  // ← 削除予定
    query: &impl MirQuery,
    mir_func: &MirFunction,
) -> Option<LoopFormIntake>

After

pub(crate) fn intake_loop_form_v2(
    loop_form: &crate::mir::loop_form::LoopForm,
    query: &impl MirQuery,
    mir_func: &MirFunction,
) -> Option<LoopFormIntake>

変更内容:

  • var_classes: &LoopVarClassBox 引数を削除
  • Trio を使わずに pinned/carrier hint を生成
  • 実際の分類は呼び出し側が LoopScopeShape::from_loop_form() で実施

5. 拡張提案

5.1 現時点では拡張不要

LoopScopeShape は既に以下を提供している:

  1. 変数分類Pinned/Carrier/BodyLocalExit/BodyLocalInternal
  2. PHI 生成判定header/exit
  3. 定義位置追跡variable_definitions
  4. exit_live 計算(保守的近似)
  5. 順序付き一覧pinned_ordered/carriers_ordered

結論: Phase 70 では既存 API のみで移行可能!

5.2 将来的な拡張候補Phase 71+

  1. 精密 liveness 解析NYASH_EXIT_LIVE_ENABLE=1

    • 現在: 保守的近似(全変数を live とみなす)
    • 将来: MIR スキャンによる精密解析LoopFormOps 拡張後)
  2. Case-A 判定の統合

    • 現在: is_case_a_minimal_target() が func_name で判定
    • 将来: LoopScopeShape に構造的判定を統合
  3. LoopFormIntake の統合

    • 現在: LoopFormIntake と LoopScopeShape が分離
    • 将来: LoopScopeShape が LoopFormIntake の役割も吸収

6. 実装手順Phase 70

6.1 ステップ 1: intake_loop_form_v2() 実装

ファイル: src/mir/join_ir/lowering/loop_form_intake.rs

変更内容:

  1. intake_loop_form_v2() を新規作成
  2. var_classes 引数を削除
  3. L169-182 の Trio 分類コードを削除
  4. pinned_hint/carrier_hint をそのまま ordered_pinned/ordered_carriers に

コード例:

/// LoopForm + MIR から pinned/carrier hint を抽出するPhase 70: Trio なし版)
pub(crate) fn intake_loop_form_v2(
    loop_form: &crate::mir::loop_form::LoopForm,
    query: &impl MirQuery,
    mir_func: &MirFunction,
) -> Option<LoopFormIntake> {
    // ... 既存の L31-167 までのコードは変更なし ...

    // Phase 70: Trio 分類を削除
    let ordered_pinned: Vec<String> = pinned_hint
        .into_iter()
        .collect::<BTreeSet<_>>()
        .into_iter()
        .collect();
    let ordered_carriers: Vec<String> = carrier_hint
        .into_iter()
        .collect::<BTreeSet<_>>()
        .into_iter()
        .collect();

    if ordered_pinned.is_empty() || ordered_carriers.is_empty() {
        return None;
    }

    Some(LoopFormIntake {
        pinned_ordered: ordered_pinned,
        carrier_ordered: ordered_carriers,
        header_snapshot: header_vals_mir,
        exit_snapshots,
        exit_preds,
    })
}

6.2 ステップ 2: 呼び出し側の移行

対象ファイル:

  • src/mir/join_ir/lowering/mod.rs(もしあれば)
  • json_v0_bridge の関連ファイル

変更内容:

  1. intake_loop_form()intake_loop_form_v2() に切り替え
  2. Trio 生成コードを削除
  3. LoopScopeShape::from_existing_boxes()LoopScopeShape::from_loop_form() に変更

コード例:

// Before
let var_classes = LoopVarClassBox::new();
let exit_live_box = LoopExitLivenessBox::new();
let intake = intake_loop_form(loop_form, &var_classes, query, mir_func)?;
let scope = LoopScopeShape::from_existing_boxes(
    loop_form, &intake, &var_classes, &exit_live_box, query, func_name
)?;

// After
let intake = intake_loop_form_v2(loop_form, query, mir_func)?;
let scope = LoopScopeShape::from_loop_form(loop_form, &intake, query, func_name)?;

6.3 ステップ 3: テスト確認

テスト対象:

  1. loop_scope_shape/tests.rs のテストが全て PASS
  2. JoinIR lowering 系のテストjson_v0_bridge 経由)
  3. 既存の PHI 生成テスト267/268 PASS 維持)

確認コマンド:

# 単体テスト
cargo test --release loop_scope_shape

# JoinIR lowering テスト
cargo test --release joinir

# 全テスト(退行チェック)
cargo test --release

6.4 ステップ 4: 旧関数の deprecation

ファイル: src/mir/join_ir/lowering/loop_form_intake.rs

変更内容:

/// 旧版Phase 70 で deprecation 予定)
#[deprecated(since = "Phase 70", note = "Use intake_loop_form_v2() instead")]
pub(crate) fn intake_loop_form(
    loop_form: &crate::mir::loop_form::LoopForm,
    var_classes: &LoopVarClassBox,
    query: &impl MirQuery,
    mir_func: &MirFunction,
) -> Option<LoopFormIntake> {
    // 互換性のため一時的に残す
    intake_loop_form_v2(loop_form, query, mir_func)
}

6.5 ステップ 5: ドキュメント更新

対象ファイル:

  • src/mir/join_ir/lowering/loop_form_intake.rs の冒頭コメント
  • src/mir/join_ir/lowering/loop_scope_shape/builder.rs の Phase 48-6 コメント

追加内容:

//! # Phase 70: Trio 依存排除完了
//!
//! - intake_loop_form_v2(): Trio を使わずに hint のみを抽出
//! - LoopScopeShape::from_loop_form(): Trio を内部化して分類実施
//! - json_v0_bridge: Trio 依存ゼロ達成!

7. 移行の安全性保証

7.1 退行防止策

  1. 段階的移行: intake_loop_form_v2() を新規作成し、旧関数を deprecation
  2. 既存テストの維持: 267/268 PASS を維持
  3. 互換レイヤー: 旧関数から新関数を呼び出して動作検証

7.2 検証ポイント

項目 検証方法 期待結果
PHI 生成 既存テスト実行 267/268 PASS 維持
pinned/carrier 判定 loop_scope_shape tests 全 PASS
exit_live 計算 JoinIR lowering テスト 変化なし
MIR パース preheader 変数抽出 s/n/i 正常抽出

7.3 ロールバック計画

Phase 70 で問題が発生した場合:

  1. intake_loop_form_v2() を削除
  2. intake_loop_form() に戻す
  3. Trio 依存を一時的に復活
  4. 問題を調査して Phase 71 で再挑戦

8. 期待される効果

8.1 コード削減

ファイル Before After 削減率
loop_form_intake.rs 211行 197行 7% 削減
json_v0_bridge 系 Trio 生成コード 削除 10-15行削減

8.2 設計改善

  1. 責務の明確化:

    • loop_form_intake: MIR パース + hint 生成
    • LoopScopeShape: 変数分類の SSOT
  2. 依存の整理:

    • json_v0_bridge: Trio を知らない
    • LoopScopeShape: Trio を内部化builder.rs のみ)
  3. 保守性向上:

    • 分類ロジックの重複を解消
    • LoopScopeShape が唯一の分類実装に

8.3 Phase 48-6 設計の完成

Phase 48-6 の目標「Trio を builder.rs のみに封じ込める」が完全達成:

  • json_v0_bridge: Trio 依存ゼロ
  • loop_form_intake: Trio 呼び出しゼロ
  • LoopScopeShape: Trio を内部化builder.rs のみ知る)

9. 補足: LoopScopeShape::from_loop_form() の既存実装

Phase 48-2 で既に実装済み(builder.rs L64-81:

/// Trio 引数なしで LoopScopeShape を構築Trio 内部化)
pub(crate) fn from_loop_form(
    loop_form: &LoopForm,
    intake: &LoopFormIntake,
    query: &impl MirQuery,
    func_name: Option<&str>,
) -> Option<Self> {
    let var_classes = LoopVarClassBox::new();
    let exit_live_box = LoopExitLivenessBox::new();

    Self::from_existing_boxes(
        loop_form,
        intake,
        &var_classes,
        &exit_live_box,
        query,
        func_name,
    )
}

重要な発見:

  • Trio の生成は 既に LoopScopeShape 内部で完結
  • json_v0_bridge が Trio を渡す必要は 全くない
  • Phase 70 は「呼び出し側を既存 API に変えるだけ」で完了!

10. まとめ

10.1 設計の核心

  1. loop_form_intake.rs: Trio 分類を削除し、hint 抽出のみに専念
  2. LoopScopeShape::from_loop_form(): 既存実装を活用(変更不要)
  3. json_v0_bridge: Trio 生成コードを削除し、from_loop_form() を呼ぶだけ

10.2 Phase 70 の作業量

  • 新規実装: intake_loop_form_v2()14行削減版
  • 呼び出し側修正: Trio 生成コードの削除
  • テスト確認: 既存テスト実行267/268 PASS 維持)

見積もり: 1-2時間の実装 + 30分のテスト確認 = 合計 2.5時間

10.3 Phase 70 完了後の状態

json_v0_bridge/
  └─ lowering/
      └─ loop_.rs
          ├─ intake_loop_form_v2() 呼び出しTrio なし)
          └─ LoopScopeShape::from_loop_form() 呼び出しTrio 内部化)

loop_scope_shape/
  └─ builder.rs
      ├─ from_loop_form() が Trio を内部生成
      └─ from_existing_boxes_legacy() が Trio を使用Phase 48-6 境界)

loop_form_intake.rs
  ├─ intake_loop_form_v2() 実装Trio なし、hint のみ)
  └─ intake_loop_form() deprecation互換性維持

Phase 48-6 設計の完全実現: Trio は builder.rs のみが知る層!


Phase 70 実装 Checklist

  • Step 1: intake_loop_form_v2() 実装loop_form_intake.rs
  • Step 2: json_v0_bridge の呼び出し側修正
  • Step 3: テスト確認267/268 PASS 維持)
  • Step 4: intake_loop_form() に deprecation マーク
  • Step 5: ドキュメント更新Phase 70 完了記録)
  • Step 6: コミット(退行なし確認済み)

実装準備完了Phase 70 で Trio 依存ゼロを達成しよう! 🚀