diff --git a/src/mir/control_form.rs b/src/mir/control_form.rs index 6ebcf599..80abc0b6 100644 --- a/src/mir/control_form.rs +++ b/src/mir/control_form.rs @@ -11,6 +11,121 @@ */ use crate::mir::{BasicBlock, BasicBlockId, MirFunction}; +use std::collections::BTreeSet; + +// ============================================================================ +// Phase 32: 新しい ID 型(LoopRegion / LoopControlShape 用) +// ============================================================================ + +/// ループを一意に識別する ID +#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] +pub struct LoopId(pub u32); + +/// 出口辺を一意に識別する ID +#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] +pub struct ExitEdgeId(pub u32); + +/// continue 辺を一意に識別する ID +#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] +pub struct ContinueEdgeId(pub u32); + +/// ループラベル(将来の labeled break/continue 用) +#[derive(Clone, Debug, Eq, PartialEq, Hash)] +pub struct LoopLabel(pub String); + +// ============================================================================ +// Phase 32: LoopRegion - ブロック集合 + ネスト構造 +// ============================================================================ + +/// ループ領域を表す箱 +/// +/// LoopShape の「形だけ」から拡張して、ブロック集合とネスト関係を持つ。 +#[derive(Debug, Clone)] +pub struct LoopRegion { + /// このループの ID + pub id: LoopId, + /// ループ直前のブロック + pub preheader: BasicBlockId, + /// ループヘッダ(条件判定) + pub header: BasicBlockId, + /// ラッチブロック群(通常は1つだが、複数の場合もある) + pub latches: Vec, + /// ループ内の全ブロック集合 + pub blocks: BTreeSet, + /// 親ループの ID(ネストの外側) + pub parent: Option, + /// 子ループの ID 群(ネストの内側) + pub children: Vec, +} + +// ============================================================================ +// Phase 32: LoopControlShape - 制御フロー辺 +// ============================================================================ + +/// ループの制御フロー辺を表す箱 +#[derive(Debug, Clone)] +pub struct LoopControlShape { + /// このループの ID + pub loop_id: LoopId, + /// continue 辺の ID 群 + pub continues: Vec, + /// 出口辺の ID 群 + pub exits: Vec, +} + +/// 出口辺を表す構造体 +#[derive(Debug, Clone)] +pub struct ExitEdge { + /// この辺の ID + pub id: ExitEdgeId, + /// どのループからの出口か(冗長だけど便利) + pub loop_id: LoopId, + /// 出発ブロック + pub from: BasicBlockId, + /// 到着ブロック + pub to: BasicBlockId, + /// 出口の種類 + pub kind: ExitKind, +} + +/// 出口辺の種類 +#[derive(Debug, Clone, Eq, PartialEq)] +pub enum ExitKind { + /// while(cond) の cond が false + ConditionFalse, + /// break 文 + Break { + /// labeled break 用(将来拡張) + label: Option, + }, + /// ループ内 return + Return, + /// throw / panic 相当 + Throw, +} + +/// continue 辺を表す構造体 +#[derive(Debug, Clone)] +pub struct ContinueEdge { + /// この辺の ID + pub id: ContinueEdgeId, + /// どのループの continue か + pub loop_id: LoopId, + /// 出発ブロック + pub from: BasicBlockId, + /// 到着ブロック(通常は latch または header) + pub to: BasicBlockId, + /// continue の種類 + pub kind: ContinueKind, +} + +/// continue 辺の種類 +#[derive(Debug, Clone, Eq, PartialEq)] +pub enum ContinueKind { + /// 通常の continue + Normal, + // 将来: Labeled { label: LoopLabel }, +} /// ループ構造の形だけを表す箱だよ。 /// @@ -168,6 +283,87 @@ pub fn is_control_form_trace_on() -> bool { } impl LoopShape { + // ======================================================================== + // Phase 32: View メソッド(段階移行用) + // ======================================================================== + + /// LoopRegion ビューを生成するよ。 + /// + /// 既存の LoopShape から LoopRegion 形式に変換する。 + /// blocks 集合は呼び出し側が後から設定するか、空のままでもOK。 + pub fn to_region_view(&self, loop_id: LoopId) -> LoopRegion { + LoopRegion { + id: loop_id, + preheader: self.preheader, + header: self.header, + latches: vec![self.latch], // 既存 LoopShape は latch 1つ + blocks: BTreeSet::new(), // 呼び出し側で設定可能 + parent: None, // ネスト情報は後から設定 + children: vec![], + } + } + + /// LoopControlShape ビューを生成するよ。 + /// + /// 既存の LoopShape から LoopControlShape 形式に変換する。 + /// 辺の ID は呼び出し側で管理するため、ここでは ID リストのみ返す。 + pub fn to_control_view(&self, loop_id: LoopId) -> LoopControlShape { + // 辺の数だけ ID を振る(0始まり、呼び出し側でオフセット可能) + let continues: Vec = self + .continue_targets + .iter() + .enumerate() + .map(|(i, _)| ContinueEdgeId(i as u32)) + .collect(); + + let exits: Vec = self + .break_targets + .iter() + .enumerate() + .map(|(i, _)| ExitEdgeId(i as u32)) + .collect(); + + LoopControlShape { + loop_id, + continues, + exits, + } + } + + /// 出口辺を生成するよ。 + /// + /// break_targets の情報から ExitEdge 群を生成する。 + pub fn to_exit_edges(&self, loop_id: LoopId) -> Vec { + self.break_targets + .iter() + .enumerate() + .map(|(i, &from)| ExitEdge { + id: ExitEdgeId(i as u32), + loop_id, + from, + to: self.exit, + kind: ExitKind::Break { label: None }, + }) + .collect() + } + + /// continue 辺を生成するよ。 + /// + /// continue_targets の情報から ContinueEdge 群を生成する。 + pub fn to_continue_edges(&self, loop_id: LoopId) -> Vec { + self.continue_targets + .iter() + .enumerate() + .map(|(i, &from)| ContinueEdge { + id: ContinueEdgeId(i as u32), + loop_id, + from, + to: self.header, // continue は header に戻る + kind: ContinueKind::Normal, + }) + .collect() + } + /// Debug ビルドでだけ呼ぶ用の簡易 invariant チェックだよ。 /// /// - preheader → header にエッジがあること diff --git a/src/mir/join_ir/lowering/loop_scope_shape.rs b/src/mir/join_ir/lowering/loop_scope_shape.rs index a692f551..c8b4cf86 100644 --- a/src/mir/join_ir/lowering/loop_scope_shape.rs +++ b/src/mir/join_ir/lowering/loop_scope_shape.rs @@ -50,6 +50,7 @@ use std::collections::{BTreeMap, BTreeSet}; +use crate::mir::control_form::LoopId; use crate::mir::join_ir::lowering::exit_args_resolver::resolve_exit_args; use crate::mir::join_ir::lowering::loop_form_intake::LoopFormIntake; use crate::mir::loop_form::LoopForm; @@ -341,6 +342,11 @@ impl LoopScopeShape { /// Phase 30 F-3.1: 従来の既存箱ベース実装(legacy path) /// /// analyze_case_a と分離することで、Case-A minimal だけ新パスを通せる。 + /// + /// # Phase 32 Step 3-B: View 経由でブロック情報を取得 + /// + /// 直接 `loop_form.header` などを読む代わりに、`to_region_view()` 経由で取得。 + /// 現在は同じ結果だが、将来 LoopRegion が独自情報を持つようになった時に差し替え可能。 fn from_existing_boxes_legacy( loop_form: &LoopForm, intake: &LoopFormIntake, @@ -348,11 +354,28 @@ impl LoopScopeShape { exit_live_box: &LoopExitLivenessBox, query: &impl MirQuery, ) -> Option { - // Extract block IDs from LoopForm - let header = loop_form.header; - let body = loop_form.body; - let latch = loop_form.latch; - let exit = loop_form.exit; + // Phase 32 Step 3-B: Extract block IDs via view (情報源を view に切り替え) + let loop_id = LoopId(0); // 単一ループの場合は 0 + let region = loop_form.to_region_view(loop_id); + let exit_edges = loop_form.to_exit_edges(loop_id); + + // View からブロック ID を取得 + let header = region.header; + let body = loop_form.body; // body は region.blocks から推測が難しいので直接参照を維持 + let latch = region.latches.first().copied().unwrap_or(loop_form.latch); + let exit = exit_edges.first().map(|e| e.to).unwrap_or(loop_form.exit); + + // Debug: view 経由の情報をログ + if std::env::var("NYASH_LOOPSCOPE_DEBUG").is_ok() { + let control = loop_form.to_control_view(loop_id); + eprintln!( + "[loopscope/view] region.header={:?}, latches={}, exit_edges={}, control.exits={}", + region.header, + region.latches.len(), + exit_edges.len(), + control.exits.len() + ); + } // Extract pinned and carriers from intake (already classified) let pinned: BTreeSet = intake.pinned_ordered.iter().cloned().collect(); diff --git a/src/mir/join_ir/lowering/loop_to_join.rs b/src/mir/join_ir/lowering/loop_to_join.rs index abe165e8..29308ffe 100644 --- a/src/mir/join_ir/lowering/loop_to_join.rs +++ b/src/mir/join_ir/lowering/loop_to_join.rs @@ -15,6 +15,7 @@ //! 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; @@ -108,6 +109,23 @@ impl LoopToJoinLowerer { ); } + // 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) }