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>
This commit is contained in:
@ -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<BasicBlockId>,
|
||||
/// ループ内の全ブロック集合
|
||||
pub blocks: BTreeSet<BasicBlockId>,
|
||||
/// 親ループの ID(ネストの外側)
|
||||
pub parent: Option<LoopId>,
|
||||
/// 子ループの ID 群(ネストの内側)
|
||||
pub children: Vec<LoopId>,
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Phase 32: LoopControlShape - 制御フロー辺
|
||||
// ============================================================================
|
||||
|
||||
/// ループの制御フロー辺を表す箱
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct LoopControlShape {
|
||||
/// このループの ID
|
||||
pub loop_id: LoopId,
|
||||
/// continue 辺の ID 群
|
||||
pub continues: Vec<ContinueEdgeId>,
|
||||
/// 出口辺の ID 群
|
||||
pub exits: Vec<ExitEdgeId>,
|
||||
}
|
||||
|
||||
/// 出口辺を表す構造体
|
||||
#[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<LoopLabel>,
|
||||
},
|
||||
/// ループ内 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<ContinueEdgeId> = self
|
||||
.continue_targets
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(i, _)| ContinueEdgeId(i as u32))
|
||||
.collect();
|
||||
|
||||
let exits: Vec<ExitEdgeId> = 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<ExitEdge> {
|
||||
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<ContinueEdge> {
|
||||
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 にエッジがあること
|
||||
|
||||
@ -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<Self> {
|
||||
// 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<String> = intake.pinned_ordered.iter().cloned().collect();
|
||||
|
||||
@ -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)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user