Files
hakorune/src/mir/join_ir/lowering/loop_to_join.rs
nyash-codex ec69b49446 feat(mir): Phase 32 Step 0-3B - LoopRegion/LoopControlShape view methods
Phase 32 introduces a "view pattern" for loop structures, enabling
gradual migration without breaking existing code.

Changes:
- control_form.rs: Add new ID types (LoopId, ExitEdgeId, ContinueEdgeId)
  and structures (LoopRegion, LoopControlShape, ExitEdge, ContinueEdge)
- control_form.rs: Add view methods on LoopShape:
  - to_region_view() - returns LoopRegion
  - to_control_view() - returns LoopControlShape
  - to_exit_edges() - returns Vec<ExitEdge>
  - to_continue_edges() - returns Vec<ContinueEdge>
- loop_scope_shape.rs: Use views in from_existing_boxes_legacy()
- loop_to_join.rs: Add debug logging with Phase 32 views

All 4 minimal lowerers (skip_ws/trim/append_defs/stage1) now use
view-based block ID extraction via shared from_existing_boxes_legacy().

Tests: joinir_runner_standalone_*, joinir_vm_bridge_trim_* PASS

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-26 08:01:32 +09:00

294 lines
10 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//! Phase 31: LoopToJoinLowerer - 統一 Loop→JoinIR 変換箱
//!
//! このモジュールは MIR の LoopForm を JoinIR に変換する統一インターフェースを提供する。
//!
//! ## 設計思想
//!
//! - **単一エントリポイント**: `LoopToJoinLowerer::lower()` ですべてのループを処理
//! - **パターン自動判定**: LoopScopeShape を解析して適切な変換を選択
//! - **既存コード再利用**: generic_case_a の `_with_scope` 関数を内部で呼び出し
//!
//! ## 使用例
//!
//! ```ignore
//! let lowerer = LoopToJoinLowerer::new();
//! let join_module = lowerer.lower(func, &loop_form, &query)?;
//! ```
use crate::mir::control_form::LoopId;
use crate::mir::join_ir::lowering::generic_case_a;
use crate::mir::join_ir::lowering::loop_form_intake::intake_loop_form;
use crate::mir::join_ir::lowering::loop_scope_shape::LoopScopeShape;
use crate::mir::join_ir::JoinModule;
use crate::mir::loop_form::LoopForm;
use crate::mir::phi_core::loop_exit_liveness::LoopExitLivenessBox;
use crate::mir::phi_core::loop_var_classifier::LoopVarClassBox;
use crate::mir::query::MirQueryBox;
use crate::mir::MirFunction;
/// Loop→JoinIR 変換の統一箱
///
/// Phase 31 で導入された統一インターフェース。
/// 全ての MIR LoopForm を JoinIR に正規化する。
pub struct LoopToJoinLowerer {
/// デバッグモード(詳細ログ出力)
debug: bool,
}
impl Default for LoopToJoinLowerer {
fn default() -> Self {
Self::new()
}
}
impl LoopToJoinLowerer {
/// 新しい LoopToJoinLowerer を作成
pub fn new() -> Self {
let debug = std::env::var("NYASH_LOOPTOJOIN_DEBUG")
.map(|v| v == "1")
.unwrap_or(false);
Self { debug }
}
/// MIR LoopForm を JoinIR に変換
///
/// # Arguments
///
/// - `func`: MIR 関数
/// - `loop_form`: 変換対象の LoopForm
/// - `func_name`: 関数名(オプション、ルーティング用)
///
/// # Returns
///
/// - `Some(JoinModule)`: 変換成功
/// - `None`: 変換失敗(フォールバック経路へ)
pub fn lower(
&self,
func: &MirFunction,
loop_form: &LoopForm,
func_name: Option<&str>,
) -> Option<JoinModule> {
if self.debug {
eprintln!(
"[LoopToJoinLowerer] lower() called for {:?}",
func_name.unwrap_or("<unknown>")
);
}
// Phase 31 Step 3-A: 早期リターン(関数名フィルタ)
// Note: scope 構築前でもチェック可能(現在は func_name のみで判定)
// Step 3-B で構造チェックを追加予定(その時は scope 構築後に移動)
if !func_name.map_or(false, super::loop_scope_shape::is_case_a_minimal_target) {
if self.debug {
eprintln!(
"[LoopToJoinLowerer] early return: {:?} is not a Case-A minimal target",
func_name.unwrap_or("<unknown>")
);
}
return None;
}
// Step 1: MirQuery を構築
let query = MirQueryBox::new(func);
// Step 2: 分類箱を構築Phase 31 では空箱、将来 MIR 解析で埋める)
let var_classes = LoopVarClassBox::new();
let exit_live = LoopExitLivenessBox::new();
// Step 3: LoopFormIntake を構築
let intake = intake_loop_form(loop_form, &var_classes, &query, func)?;
// Step 4: LoopScopeShape を構築
let scope =
LoopScopeShape::from_existing_boxes(loop_form, &intake, &var_classes, &exit_live, &query, func_name)?;
if self.debug {
eprintln!(
"[LoopToJoinLowerer] LoopScopeShape built: pinned={:?}, carriers={:?}, exit_live={:?}",
scope.pinned, scope.carriers, scope.exit_live
);
}
// Phase 32 Step 3-A: View メソッドを使った構造確認(段階移行)
if self.debug {
let loop_id = LoopId(0); // 単一ループの場合は 0
let region = loop_form.to_region_view(loop_id);
let control = loop_form.to_control_view(loop_id);
let exit_edges = loop_form.to_exit_edges(loop_id);
let continue_edges = loop_form.to_continue_edges(loop_id);
eprintln!(
"[LoopToJoinLowerer] Phase 32 views: region.header={:?}, control.exits={}, exit_edges={}, continue_edges={}",
region.header,
control.exits.len(),
exit_edges.len(),
continue_edges.len()
);
}
// Step 5: パターンに応じた lowering を実行
self.lower_with_scope(scope, func_name)
}
/// Case-A ループとしてサポートされているかチェック
///
/// Phase 31 Step 3-B: 関数名フィルタ + 構造チェック
///
/// # Case-A の定義
///
/// - 単一出口break_targets が 1 箇所以下)
/// - ループ変数または固定変数が存在
/// - ネストループなし(将来チェック追加予定)
///
/// # Arguments
///
/// - `loop_form`: LoopForm構造判定用
/// - `scope`: LoopScopeShape変数分類用
/// - `func_name`: 関数名Step 3-C まで限定フィルタ)
///
/// # Returns
///
/// - `true`: Case-A として lowering 可能
/// - `false`: 未サポート(フォールバック経路へ)
#[allow(dead_code)] // Step 3-C/D で使用予定
pub(crate) fn is_supported_case_a_loop(
&self,
loop_form: &LoopForm,
scope: &LoopScopeShape,
func_name: Option<&str>,
) -> bool {
// Phase 31 Step 3-A: 関数名フィルタStep 3-D で撤去予定)
if !func_name.map_or(false, super::loop_scope_shape::is_case_a_minimal_target) {
return false;
}
// Phase 31 Step 3-B: 構造チェック(追加)
// 単一出口 (break が 1 箇所以下)
if loop_form.break_targets.len() > 1 {
if self.debug {
eprintln!(
"[LoopToJoinLowerer] rejected: multiple break targets ({})",
loop_form.break_targets.len()
);
}
return false;
}
// ループ変数または固定変数がある(空ループは対象外)
if scope.carriers.is_empty() && scope.pinned.is_empty() {
if self.debug {
eprintln!("[LoopToJoinLowerer] rejected: no carriers or pinned vars");
}
return false;
}
true
}
/// LoopScopeShape から JoinModule を生成(内部メソッド)
///
/// Phase 31 Step 2: 関数名で 4 パターンにディスパッチ
/// Step 3 で汎用 Case-A lowering に統一予定
fn lower_with_scope(
&self,
scope: LoopScopeShape,
func_name: Option<&str>,
) -> Option<JoinModule> {
let name = func_name.unwrap_or("");
// Phase 31: matches! で完全一致is_case_a_minimal_target と同じ条件)
let result = match name {
"Main.skip/1" => {
if self.debug {
eprintln!("[LoopToJoinLowerer] dispatching to skip_ws lowerer");
}
generic_case_a::lower_case_a_skip_ws_with_scope(scope)
}
"FuncScannerBox.trim/1" => {
if self.debug {
eprintln!("[LoopToJoinLowerer] dispatching to trim lowerer");
}
generic_case_a::lower_case_a_trim_with_scope(scope)
}
"FuncScannerBox.append_defs/2" => {
if self.debug {
eprintln!("[LoopToJoinLowerer] dispatching to append_defs lowerer");
}
generic_case_a::lower_case_a_append_defs_with_scope(scope)
}
"Stage1UsingResolverBox.resolve_for_source/5" => {
if self.debug {
eprintln!("[LoopToJoinLowerer] dispatching to stage1 lowerer");
}
generic_case_a::lower_case_a_stage1_usingresolver_with_scope(scope)
}
_ => {
// TODO: Phase 31 Step 3 で汎用 Case A 対応
if self.debug {
eprintln!(
"[LoopToJoinLowerer] no matching pattern for {:?}, returning None",
name
);
}
None
}
};
result
}
// ========================================
// Convenience methods for specific patterns
// ========================================
/// Main.skip/1 専用の lowering
///
/// Phase 31 Step 1 の検証用メソッド。
/// 既存の `skip_ws.rs` からの移行確認に使用。
pub fn lower_minimal_skip_ws_case_a(
&self,
func: &MirFunction,
loop_form: &LoopForm,
) -> Option<JoinModule> {
self.lower(func, loop_form, Some("Main.skip/1"))
}
/// FuncScannerBox.trim/1 専用の lowering
pub fn lower_minimal_trim_case_a(
&self,
func: &MirFunction,
loop_form: &LoopForm,
) -> Option<JoinModule> {
self.lower(func, loop_form, Some("FuncScannerBox.trim/1"))
}
/// FuncScannerBox.append_defs/2 専用の lowering
pub fn lower_minimal_append_defs_case_a(
&self,
func: &MirFunction,
loop_form: &LoopForm,
) -> Option<JoinModule> {
self.lower(func, loop_form, Some("FuncScannerBox.append_defs/2"))
}
/// Stage1UsingResolverBox.resolve_for_source/5 専用の lowering
pub fn lower_minimal_stage1_case_a(
&self,
func: &MirFunction,
loop_form: &LoopForm,
) -> Option<JoinModule> {
self.lower(func, loop_form, Some("Stage1UsingResolverBox.resolve_for_source/5"))
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_lowerer_creation() {
let lowerer = LoopToJoinLowerer::new();
assert!(!lowerer.debug || lowerer.debug); // Just check it compiles
}
}