feat(mir): Phase 30 F-1 LoopScopeShape SSOT preparation

LoopScopeShape を変数分類の唯一の情報源 (SSOT) にするための準備:

F-1.1 LoopVarClassBox:
- 4分類(Pinned/Carrier/BodyLocalExit/BodyLocalInternal)の仕様を
  loop_scope_shape.rs にドキュメント化(PHI生成ルール表付き)
- LoopScopeShape.classify() / classify_all() メソッド追加
- LoopVarClassBox.classify_with_scope() 委譲メソッド追加
- 旧APIにPhase 30 TODOコメント追加

F-1.2 LoopExitLivenessBox:
- exit_live フィールドにSSOT説明ドキュメント追加
- get_exit_live_from_scope() 委譲メソッド追加

F-1.3 LocalScopeInspectorBox:
- Phase 30移行中のTODOコメント追加
- is_available_in_all_with_scope() 委譲メソッド追加

未使用フィールド削除:
- CaseAContext::scope フィールド削除
- LoopBypassFlags::exit フィールド削除
- PhiBuilderBox::loop_context / LoopPhiContext 削除

テスト結果: 37テスト全てPASS
- loop_scope_shape: 12 PASS (+2 new)
- loop_var_classifier: 11 PASS
- loop_exit_liveness: 3 PASS
- local_scope_inspector: 11 PASS

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

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
nyash-codex
2025-11-25 15:14:54 +09:00
parent e93727dd37
commit de5d5fae52
6 changed files with 576 additions and 33 deletions

View File

@ -51,8 +51,7 @@ pub(crate) fn is_joinir_header_bypass_target(fn_name: &str) -> bool {
pub(crate) struct LoopBypassFlags {
/// Header φ バイパスが有効か
pub header: bool,
/// Exit φ バイパスが有効かPhase 27.6-2, 現在未使用
pub exit: bool,
// Phase 30: exit フィールド削除(完全未使用、将来 JoinIR で代替予定
}
/// Phase 27.4-C Refactor: JoinIR Loop φ バイパスフラグを取得
@ -80,8 +79,7 @@ pub(crate) fn get_loop_bypass_flags(fn_name: &str) -> LoopBypassFlags {
LoopBypassFlags {
header: joinir_exp && header_exp && is_joinir_header_bypass_target(fn_name),
// Phase 27.6-2: Exit φ バイパスは将来的に追加予定
exit: false,
// Phase 30: exit フィールド削除済み
}
}

View File

@ -1,5 +1,14 @@
/// LocalScopeInspectorBox - Variable definition tracker
///
/// # Phase 30: LoopScopeShape 移行中
///
/// このBoxは将来 LoopScopeShape に吸収される予定。
/// 定義位置情報は LoopScopeShape::from_existing_boxes() 内部で集約され、
/// 変数分類に使用される。
///
/// **新規コード**: LoopScopeShape が利用可能な場合は、
/// `classify()` メソッドを直接使うことを推奨。
///
/// # Purpose
///
/// This box tracks which variables are defined in which basic blocks.
@ -145,6 +154,30 @@ impl LocalScopeInspectorBox {
.map(|blocks| blocks.len())
.unwrap_or(0)
}
// ========================================================================
// Phase 30 F-1.3: LoopScopeShape 委譲メソッド
// ========================================================================
/// Phase 30: LoopScopeShape を使って変数が全 exit pred で利用可能か判定
///
/// 新規コードでは LoopScopeShape::classify() を直接使うことを推奨。
/// このメソッドは LoopScopeShape が既にある場合の便利メソッド。
///
/// # Note
///
/// LoopScopeShape::classify() は既に exit_live 情報を含んでいるため、
/// 直接 classify() → needs_exit_phi() を使う方が効率的。
pub fn is_available_in_all_with_scope(
&self,
var_name: &str,
scope: &crate::mir::join_ir::lowering::loop_scope_shape::LoopScopeShape,
) -> bool {
// LoopScopeShape の分類を使用
// Pinned/Carrier/BodyLocalExit → available in all (exit PHI needed)
// BodyLocalInternal → NOT available in all (no exit PHI)
scope.needs_exit_phi(var_name)
}
}
// ============================================================================

View File

@ -43,6 +43,13 @@ pub trait ExitLivenessProvider: Send + Sync {
/// Loop Exit Liveness BoxLegacy/Phase 1
///
/// # Phase 30: LoopScopeShape 移行中
///
/// このBoxは将来 LoopScopeShape に吸収される予定。
/// LoopScopeShape.exit_live が唯一の live_at_exit 情報源になる。
///
/// **新規コード**: `LoopScopeShape::exit_live` を直接参照すること。
///
/// # Purpose
/// Exit後で本当に使われる変数を決定する専門箱
///
@ -171,6 +178,29 @@ impl LoopExitLivenessBox {
live_vars
}
// ========================================================================
// Phase 30 F-1.2: LoopScopeShape 委譲メソッド
// ========================================================================
/// Phase 30: LoopScopeShape の exit_live を直接取得
///
/// 新規コードではこのメソッドを使うことを推奨。
/// 将来的には旧 compute_live_at_exit() メソッドを削除し、
/// LoopScopeShape::exit_live を直接参照するのが標準になる。
///
/// # Example
///
/// ```ignore
/// let scope = LoopScopeShape::from_existing_boxes(...)?;
/// let live = liveness_box.get_exit_live_from_scope(&scope);
/// ```
pub fn get_exit_live_from_scope(
&self,
scope: &crate::mir::join_ir::lowering::loop_scope_shape::LoopScopeShape,
) -> BTreeSet<String> {
scope.exit_live.clone()
}
}
impl ExitLivenessProvider for LoopExitLivenessBox {

View File

@ -108,7 +108,12 @@ impl LoopVarClass {
/// Loop variable classifier box
///
/// # Usage
/// # Phase 30: LoopScopeShape 移行中
///
/// このBoxは将来 LoopScopeShape に吸収される予定。
/// 新規コードは `LoopScopeShape::classify()` を直接使うことを推奨。
///
/// # Usage (Legacy)
///
/// ```
/// let inspector = LocalScopeInspectorBox::new();
@ -127,6 +132,13 @@ impl LoopVarClass {
/// // Generate exit PHI
/// }
/// ```
///
/// # Usage (Phase 30 Recommended)
///
/// ```
/// // LoopScopeShape が利用可能な場合は直接使う
/// let class = scope.classify("ch");
/// ```
#[derive(Debug, Clone, Default)]
pub struct LoopVarClassBox;
@ -138,6 +150,11 @@ impl LoopVarClassBox {
/// Classify a variable for PHI generation decision
///
/// # Phase 30 TODO
///
/// このメソッドは将来 `LoopScopeShape::classify()` に置き換える予定。
/// 呼び出し側が LoopScopeShape を持っている場合は、そちらを直接使うこと。
///
/// # Parameters
///
/// - `var_name`: Variable to classify
@ -245,6 +262,38 @@ impl LoopVarClassBox {
.cloned()
.collect()
}
// ========================================================================
// Phase 30 F-1.1: LoopScopeShape 委譲メソッド
// ========================================================================
/// Phase 30: LoopScopeShape を使って変数を分類
///
/// 新規コードではこのメソッドを使うことを推奨。
/// 将来的には旧 classify() メソッドを削除し、このメソッドが標準になる。
///
/// # Example
///
/// ```ignore
/// let scope = LoopScopeShape::from_existing_boxes(...)?;
/// let class = classifier.classify_with_scope("ch", &scope);
/// ```
pub fn classify_with_scope(
&self,
var_name: &str,
scope: &crate::mir::join_ir::lowering::loop_scope_shape::LoopScopeShape,
) -> LoopVarClass {
scope.classify(var_name)
}
/// Phase 30: LoopScopeShape を使って複数変数を一括分類
pub fn classify_all_with_scope(
&self,
var_names: &[String],
scope: &crate::mir::join_ir::lowering::loop_scope_shape::LoopScopeShape,
) -> Vec<(String, LoopVarClass)> {
scope.classify_all(var_names)
}
}
// ============================================================================

View File

@ -51,8 +51,7 @@ use std::collections::BTreeMap;
pub struct PhiBuilderBox {
/// If PHI生成時のコンテキスト将来拡張用
if_context: Option<IfPhiContext>,
/// Loop PHI生成時のコンテキスト将来拡張用
loop_context: Option<LoopPhiContext>,
// Phase 30: loop_context 削除(完全未使用、将来 JoinIR で代替予定
}
/// If PHI生成コンテキストPhase 26-F-2: 箱理論による責務分離)
@ -85,19 +84,13 @@ pub struct IfPhiContext {
pub loop_carrier_names: std::collections::BTreeSet<String>,
}
/// Loop PHI生成コンテキスト将来拡張用
#[derive(Debug, Clone)]
struct LoopPhiContext {
/// 予約済みPhase 3で実装
_reserved: (),
}
// Phase 30: LoopPhiContext 削除(完全未使用、将来 JoinIR で代替予定
impl PhiBuilderBox {
/// 新しいPhiBuilderBoxを作成
pub fn new() -> Self {
Self {
if_context: None,
loop_context: None,
}
}
@ -576,7 +569,7 @@ mod tests {
fn test_phi_builder_box_creation() {
let builder = PhiBuilderBox::new();
assert!(builder.if_context.is_none());
assert!(builder.loop_context.is_none());
// Phase 30: loop_context 削除済み
}
#[test]