Remove Trio boxes and tidy loop scope warnings
This commit is contained in:
@ -3,7 +3,7 @@
|
||||
//! 制約(必読):
|
||||
//! - 条件式の中身を解析しない(Compare/BinOp を MIR そのままコピーするだけ)
|
||||
//! - 多重ヘッダ/ネストループは対象外(v1 は minimal_ssa_skip_ws の単純ループ専用)
|
||||
//! - pinned/carrier/exit は LoopVarClassBox / LoopExitLivenessBox から渡された前提で扱う
|
||||
//! - pinned/carrier/exit は LoopScopeShape から渡された前提で扱う
|
||||
//! - 解析に失敗したら必ず None を返し、呼び元にフォールバックさせる
|
||||
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
@ -4,9 +4,10 @@
|
||||
//! - LoopForm + MirQuery + MirFunction から、JoinIR 降下に必要な情報を抽出する。
|
||||
//! - pinned/carrier 推定と ValueId マッピング、header/exit スナップショット収集を一元化。
|
||||
//! - generic_case_a/B など複数ロワーで再利用するための「入口箱」だよ。
|
||||
//!
|
||||
//! Phase 70-1: Trio (LocalScopeInspectorBox, LoopVarClassBox) 依存削除
|
||||
//! - 変数分類は LoopScopeShape::from_loop_form() に一本化(二重分類問題解消)
|
||||
|
||||
use crate::mir::phi_core::local_scope_inspector::LocalScopeInspectorBox;
|
||||
use crate::mir::phi_core::loop_var_classifier::{LoopVarClass, LoopVarClassBox};
|
||||
use crate::mir::{BasicBlockId, MirFunction, MirInstruction, MirQuery, ValueId};
|
||||
use std::collections::{BTreeMap, BTreeSet};
|
||||
|
||||
@ -21,10 +22,12 @@ pub(crate) struct LoopFormIntake {
|
||||
|
||||
/// LoopForm + MIR から pinned/carrier とスナップショットを抽出する。
|
||||
///
|
||||
/// Phase 70-1: var_classes 引数削除(Trio 依存排除)
|
||||
/// 実際の変数分類は呼び出し側が LoopScopeShape::from_loop_form() で実施
|
||||
///
|
||||
/// 失敗時は None(フォールバック用)。
|
||||
pub(crate) fn intake_loop_form(
|
||||
loop_form: &crate::mir::loop_form::LoopForm,
|
||||
var_classes: &LoopVarClassBox,
|
||||
query: &impl MirQuery,
|
||||
mir_func: &MirFunction,
|
||||
) -> Option<LoopFormIntake> {
|
||||
@ -165,36 +168,10 @@ pub(crate) fn intake_loop_form(
|
||||
}
|
||||
}
|
||||
|
||||
// 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();
|
||||
// Phase 70-1: 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();
|
||||
|
||||
if ordered_pinned.is_empty() || ordered_carriers.is_empty() {
|
||||
return None;
|
||||
|
||||
@ -3,94 +3,44 @@
|
||||
//! LoopForm / 既存箱から LoopScopeShape を構築し、Case-A minimal ターゲットは
|
||||
//! analyze_case_a パスにルーティングする。
|
||||
//!
|
||||
//! # Phase 48-6: Trio 依存の境界
|
||||
//!
|
||||
//! このファイルは **唯一 Trio(LoopVarClassBox/LoopExitLivenessBox/LocalScopeInspectorBox)を
|
||||
//! 知らないといけない層** として設計されている。
|
||||
//!
|
||||
//! ## Trio が表に出る箇所(意図的に許容)
|
||||
//!
|
||||
//! 1. **builder.rs**(このファイル): from_existing_boxes_legacy とその helper 関数
|
||||
//! 2. **phi_core/* 自身**: Trio の実装ファイル(保持)
|
||||
//! 3. **legacy bridge**: json_v0_bridge/lowering/loop_.rs(Phase 62+ で段階廃止)
|
||||
//! 4. **テスト**: loop_scope_shape/tests.rs, loop_form_intake.rs(検証用)
|
||||
//!
|
||||
//! ## 外部からの利用
|
||||
//!
|
||||
//! 外部(JoinIR lowering, LoopToJoinLowerer 等)は **LoopScopeShape の API のみ** を使用し、
|
||||
//! Trio の存在を知らない設計になっている(Phase 48-2/48-4 完了)。
|
||||
//! Trio legacy boxes は完全に除去済み。
|
||||
//! LoopForm / LoopFormIntake から LoopScopeShape を構築し、変数分類と定義位置を
|
||||
//! LoopScopeShape の内部に閉じ込める。
|
||||
|
||||
use std::collections::{BTreeMap, BTreeSet};
|
||||
|
||||
use crate::mir::control_form::LoopId;
|
||||
use crate::mir::join_ir::lowering::loop_form_intake::LoopFormIntake;
|
||||
use crate::mir::loop_form::LoopForm;
|
||||
// Phase 48-6: Trio 依存(builder.rs のみが知る層)
|
||||
use crate::mir::phi_core::local_scope_inspector::LocalScopeInspectorBox;
|
||||
use crate::mir::phi_core::loop_exit_liveness::LoopExitLivenessBox;
|
||||
use crate::mir::phi_core::loop_var_classifier::{LoopVarClass, LoopVarClassBox};
|
||||
use crate::mir::{BasicBlockId, MirQuery};
|
||||
|
||||
use super::case_a::{is_case_a_minimal_target, validate_case_a_structural};
|
||||
use super::shape::LoopScopeShape;
|
||||
use super::shape::{LoopScopeShape, LoopVarClass};
|
||||
|
||||
impl LoopScopeShape {
|
||||
/// Case-A ルーティング込みで LoopScopeShape を構築
|
||||
pub(crate) fn from_existing_boxes(
|
||||
pub(crate) fn from_loop_form(
|
||||
loop_form: &LoopForm,
|
||||
intake: &LoopFormIntake,
|
||||
var_classes: &LoopVarClassBox,
|
||||
exit_live_box: &LoopExitLivenessBox,
|
||||
query: &impl MirQuery,
|
||||
_query: &impl MirQuery,
|
||||
func_name: Option<&str>,
|
||||
) -> Option<Self> {
|
||||
if let Some(name) = func_name {
|
||||
if is_case_a_minimal_target(name) {
|
||||
return Self::analyze_case_a(
|
||||
loop_form,
|
||||
intake,
|
||||
var_classes,
|
||||
exit_live_box,
|
||||
query,
|
||||
name,
|
||||
);
|
||||
return Self::analyze_case_a(loop_form, intake, name);
|
||||
}
|
||||
}
|
||||
|
||||
Self::from_existing_boxes_legacy(loop_form, intake, var_classes, exit_live_box, query)
|
||||
}
|
||||
|
||||
/// 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,
|
||||
)
|
||||
Self::build_from_intake(loop_form, intake)
|
||||
}
|
||||
|
||||
/// Case-A minimal 用の解析パス(Phase 48-5: 構造判定検証追加)
|
||||
fn analyze_case_a(
|
||||
loop_form: &LoopForm,
|
||||
intake: &LoopFormIntake,
|
||||
var_classes: &LoopVarClassBox,
|
||||
exit_live_box: &LoopExitLivenessBox,
|
||||
query: &impl MirQuery,
|
||||
func_name: &str,
|
||||
) -> Option<Self> {
|
||||
let result =
|
||||
Self::from_existing_boxes_legacy(loop_form, intake, var_classes, exit_live_box, query)?;
|
||||
let result = Self::build_from_intake(loop_form, intake)?;
|
||||
|
||||
// Phase 48-5: 構造判定検証(警告のみ、将来的に厳格化)
|
||||
validate_case_a_structural(loop_form, &result, func_name);
|
||||
@ -108,25 +58,9 @@ impl LoopScopeShape {
|
||||
Some(result)
|
||||
}
|
||||
|
||||
/// 既存箱ベースの従来実装(Case-A 以外のループで使用)
|
||||
///
|
||||
/// # Phase 48-6: Trio を知らないといけない唯一の層
|
||||
///
|
||||
/// この関数は **Trio(LoopVarClassBox/LoopExitLivenessBox/LocalScopeInspectorBox)を
|
||||
/// 直接受け取り、LoopScopeShape に変換する責務** を持つ。
|
||||
///
|
||||
/// - **外部からは呼ばれない**: from_loop_form() が Trio を内部生成して隠蔽(Phase 48-2)
|
||||
/// - **Legacy bridge のみ**: json_v0_bridge/lowering/loop_.rs が直接呼ぶ(Phase 62+ 廃止予定)
|
||||
/// - **helper 関数**: 下記3関数も Trio を使用(このファイル内でのみ可視)
|
||||
/// - build_inspector(): LocalScopeInspectorBox 構築
|
||||
/// - classify_body_and_exit(): LoopVarClassBox 使用
|
||||
/// - merge_exit_live_from_box(): LoopExitLivenessBox 使用
|
||||
fn from_existing_boxes_legacy(
|
||||
fn build_from_intake(
|
||||
loop_form: &LoopForm,
|
||||
intake: &LoopFormIntake,
|
||||
var_classes: &LoopVarClassBox,
|
||||
exit_live_box: &LoopExitLivenessBox,
|
||||
query: &impl MirQuery,
|
||||
) -> Option<Self> {
|
||||
let layout = block_layout(loop_form);
|
||||
|
||||
@ -145,18 +79,16 @@ impl LoopScopeShape {
|
||||
let pinned: BTreeSet<String> = intake.pinned_ordered.iter().cloned().collect();
|
||||
let carriers: BTreeSet<String> = intake.carrier_ordered.iter().cloned().collect();
|
||||
|
||||
let inspector = build_inspector(intake, layout.exit);
|
||||
let (body_locals, mut exit_live) =
|
||||
classify_body_and_exit(var_classes, intake, &inspector, &layout);
|
||||
|
||||
let exit_live_from_box =
|
||||
merge_exit_live_from_box(exit_live_box, query, intake, layout.exit);
|
||||
for name in exit_live_from_box {
|
||||
exit_live.insert(name);
|
||||
}
|
||||
let variable_definitions = collect_variable_definitions(intake, &layout);
|
||||
let (body_locals, exit_live) = classify_body_and_exit(
|
||||
intake,
|
||||
&pinned,
|
||||
&carriers,
|
||||
&variable_definitions,
|
||||
&layout,
|
||||
);
|
||||
|
||||
let progress_carrier = carriers.iter().next().cloned();
|
||||
let variable_definitions = extract_variable_definitions(&inspector);
|
||||
|
||||
Some(Self {
|
||||
header: layout.header,
|
||||
@ -199,43 +131,61 @@ fn block_layout(loop_form: &LoopForm) -> LoopBlockLayout {
|
||||
}
|
||||
}
|
||||
|
||||
/// Phase 48-6: Trio 依存 helper(LocalScopeInspectorBox 構築)
|
||||
///
|
||||
/// LocalScopeInspectorBox に header/exit snapshot を登録して変数定義解析の土台を作る。
|
||||
/// この関数は from_existing_boxes_legacy からのみ呼ばれ、Trio を直接扱う。
|
||||
fn build_inspector(intake: &LoopFormIntake, exit: BasicBlockId) -> LocalScopeInspectorBox {
|
||||
let mut inspector = LocalScopeInspectorBox::new();
|
||||
inspector.record_snapshot(exit, &intake.header_snapshot);
|
||||
for (bb, snap) in &intake.exit_snapshots {
|
||||
inspector.record_snapshot(*bb, snap);
|
||||
fn collect_variable_definitions(
|
||||
intake: &LoopFormIntake,
|
||||
layout: &LoopBlockLayout,
|
||||
) -> BTreeMap<String, BTreeSet<BasicBlockId>> {
|
||||
let mut var_defs: BTreeMap<String, BTreeSet<BasicBlockId>> = BTreeMap::new();
|
||||
|
||||
for var_name in intake.header_snapshot.keys() {
|
||||
var_defs
|
||||
.entry(var_name.clone())
|
||||
.or_default()
|
||||
.insert(layout.exit);
|
||||
var_defs
|
||||
.entry(var_name.clone())
|
||||
.or_default()
|
||||
.insert(layout.header);
|
||||
}
|
||||
inspector
|
||||
|
||||
for (bb, snap) in &intake.exit_snapshots {
|
||||
for var_name in snap.keys() {
|
||||
var_defs
|
||||
.entry(var_name.clone())
|
||||
.or_default()
|
||||
.insert(*bb);
|
||||
}
|
||||
}
|
||||
|
||||
var_defs
|
||||
}
|
||||
|
||||
/// Phase 48-6: Trio 依存 helper(LoopVarClassBox による変数分類)
|
||||
///
|
||||
/// LoopVarClassBox::classify_all() を呼び出して変数を 4分類し、
|
||||
/// body_locals と exit_live に振り分ける。
|
||||
/// この関数は from_existing_boxes_legacy からのみ呼ばれ、Trio を直接扱う。
|
||||
fn classify_body_and_exit(
|
||||
var_classes: &LoopVarClassBox,
|
||||
intake: &LoopFormIntake,
|
||||
inspector: &LocalScopeInspectorBox,
|
||||
pinned: &BTreeSet<String>,
|
||||
carriers: &BTreeSet<String>,
|
||||
variable_definitions: &BTreeMap<String, BTreeSet<BasicBlockId>>,
|
||||
layout: &LoopBlockLayout,
|
||||
) -> (BTreeSet<String>, BTreeSet<String>) {
|
||||
let all_names: Vec<String> = intake.header_snapshot.keys().cloned().collect();
|
||||
let classified = var_classes.classify_all(
|
||||
&all_names,
|
||||
&intake.pinned_ordered,
|
||||
&intake.carrier_ordered,
|
||||
inspector,
|
||||
&intake.exit_preds,
|
||||
);
|
||||
|
||||
let mut body_locals: BTreeSet<String> = BTreeSet::new();
|
||||
let mut exit_live: BTreeSet<String> = BTreeSet::new();
|
||||
|
||||
for (name, class) in &classified {
|
||||
let mut all_names: BTreeSet<String> = intake.header_snapshot.keys().cloned().collect();
|
||||
for (_, snap) in &intake.exit_snapshots {
|
||||
all_names.extend(snap.keys().cloned());
|
||||
}
|
||||
all_names.extend(pinned.iter().cloned());
|
||||
all_names.extend(carriers.iter().cloned());
|
||||
|
||||
for name in all_names {
|
||||
let class = classify_var(
|
||||
&name,
|
||||
pinned,
|
||||
carriers,
|
||||
&intake.exit_preds,
|
||||
variable_definitions,
|
||||
);
|
||||
|
||||
match class {
|
||||
LoopVarClass::Pinned | LoopVarClass::Carrier => {
|
||||
exit_live.insert(name.clone());
|
||||
@ -263,40 +213,42 @@ fn classify_body_and_exit(
|
||||
(body_locals, exit_live)
|
||||
}
|
||||
|
||||
/// Phase 48-6: Trio 依存 helper(LoopExitLivenessBox による exit_live 計算)
|
||||
///
|
||||
/// LoopExitLivenessBox::compute_live_at_exit() を呼び出して、
|
||||
/// ループ終了時に live な変数集合を取得する。
|
||||
/// この関数は from_existing_boxes_legacy からのみ呼ばれ、Trio を直接扱う。
|
||||
fn merge_exit_live_from_box(
|
||||
exit_live_box: &LoopExitLivenessBox,
|
||||
query: &impl MirQuery,
|
||||
intake: &LoopFormIntake,
|
||||
exit_block: BasicBlockId,
|
||||
) -> BTreeSet<String> {
|
||||
exit_live_box.compute_live_at_exit(
|
||||
query,
|
||||
exit_block,
|
||||
&intake.header_snapshot,
|
||||
&intake.exit_snapshots,
|
||||
)
|
||||
fn classify_var(
|
||||
var_name: &str,
|
||||
pinned: &BTreeSet<String>,
|
||||
carriers: &BTreeSet<String>,
|
||||
exit_preds: &[BasicBlockId],
|
||||
variable_definitions: &BTreeMap<String, BTreeSet<BasicBlockId>>,
|
||||
) -> LoopVarClass {
|
||||
if var_name.starts_with("__pin$") && var_name.contains("$@") {
|
||||
return LoopVarClass::BodyLocalInternal;
|
||||
}
|
||||
|
||||
if pinned.contains(var_name) {
|
||||
return LoopVarClass::Pinned;
|
||||
}
|
||||
|
||||
if carriers.contains(var_name) {
|
||||
return LoopVarClass::Carrier;
|
||||
}
|
||||
|
||||
if is_available_in_all(var_name, exit_preds, variable_definitions) {
|
||||
LoopVarClass::BodyLocalExit
|
||||
} else {
|
||||
LoopVarClass::BodyLocalInternal
|
||||
}
|
||||
}
|
||||
|
||||
/// Phase 48-4: LocalScopeInspectorBox から variable_definitions を抽出
|
||||
///
|
||||
/// inspector.all_variables() と get_defining_blocks() を使って、
|
||||
/// 変数名 → 定義ブロック集合のマッピングを構築する。
|
||||
/// この関数は from_existing_boxes_legacy からのみ呼ばれ、Trio を直接扱う。
|
||||
fn extract_variable_definitions(
|
||||
inspector: &LocalScopeInspectorBox,
|
||||
) -> BTreeMap<String, BTreeSet<BasicBlockId>> {
|
||||
let mut var_defs = BTreeMap::new();
|
||||
for var_name in inspector.all_variables() {
|
||||
let blocks: BTreeSet<BasicBlockId> = inspector
|
||||
.get_defining_blocks(&var_name)
|
||||
.into_iter()
|
||||
.collect();
|
||||
var_defs.insert(var_name, blocks);
|
||||
fn is_available_in_all(
|
||||
var_name: &str,
|
||||
required_blocks: &[BasicBlockId],
|
||||
variable_definitions: &BTreeMap<String, BTreeSet<BasicBlockId>>,
|
||||
) -> bool {
|
||||
if let Some(defining_blocks) = variable_definitions.get(var_name) {
|
||||
required_blocks
|
||||
.iter()
|
||||
.all(|block| defining_blocks.contains(block))
|
||||
} else {
|
||||
false
|
||||
}
|
||||
var_defs
|
||||
}
|
||||
|
||||
@ -16,7 +16,6 @@ mod structural;
|
||||
pub(crate) use case_a::is_case_a_minimal_target;
|
||||
pub(crate) use context::CaseAContext;
|
||||
pub(crate) use shape::LoopScopeShape;
|
||||
pub(crate) use structural::LoopStructuralAnalysis;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
@ -4,9 +4,30 @@
|
||||
|
||||
use std::collections::{BTreeMap, BTreeSet};
|
||||
|
||||
use crate::mir::phi_core::loop_var_classifier::LoopVarClass;
|
||||
use crate::mir::BasicBlockId;
|
||||
|
||||
/// Variable classification for loop PHI generation.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum LoopVarClass {
|
||||
Pinned,
|
||||
Carrier,
|
||||
BodyLocalExit,
|
||||
BodyLocalInternal,
|
||||
}
|
||||
|
||||
impl LoopVarClass {
|
||||
#[cfg(test)]
|
||||
pub fn needs_exit_phi(self) -> bool {
|
||||
matches!(self, LoopVarClass::Pinned | LoopVarClass::Carrier | LoopVarClass::BodyLocalExit)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub fn needs_header_phi(self) -> bool {
|
||||
matches!(self, LoopVarClass::Pinned | LoopVarClass::Carrier)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// ループ変数スコープの統合ビュー
|
||||
///
|
||||
/// ## 4分類の定義
|
||||
@ -32,7 +53,7 @@ use crate::mir::BasicBlockId;
|
||||
/// - Block IDs: `header`, `body`, `latch`, `exit`
|
||||
/// - Variable classification: `pinned`, `carriers`, `body_locals`, `exit_live`
|
||||
/// - `progress_carrier`: 進捗チェック用(将来の Verifier で使用予定)
|
||||
/// - `variable_definitions`: LocalScopeInspectorBox 情報統合予定(Phase 48-5+)
|
||||
/// - `variable_definitions`: definition blocks collected from LoopFormIntake snapshots
|
||||
#[derive(Debug, Clone)]
|
||||
#[allow(dead_code)] // Block IDs and progress_carrier are reserved for future F-3/F-4 use
|
||||
pub(crate) struct LoopScopeShape {
|
||||
@ -50,12 +71,13 @@ pub(crate) struct LoopScopeShape {
|
||||
|
||||
impl LoopScopeShape {
|
||||
/// header PHI が必要か判定
|
||||
#[allow(dead_code)] // Phase 30: will be used in F-3 generic lowering
|
||||
#[cfg(test)]
|
||||
pub fn needs_header_phi(&self, var_name: &str) -> bool {
|
||||
self.pinned.contains(var_name) || self.carriers.contains(var_name)
|
||||
}
|
||||
|
||||
/// exit PHI が必要か判定
|
||||
#[cfg(test)]
|
||||
pub fn needs_exit_phi(&self, var_name: &str) -> bool {
|
||||
self.exit_live.contains(var_name)
|
||||
}
|
||||
@ -70,21 +92,8 @@ impl LoopScopeShape {
|
||||
self.carriers.iter().cloned().collect()
|
||||
}
|
||||
|
||||
/// header PHI 対象(pinned + carriers)
|
||||
#[allow(dead_code)] // Phase 30: will be used in F-3 generic lowering
|
||||
pub fn header_phi_vars(&self) -> Vec<String> {
|
||||
let mut result: Vec<String> = self.pinned.iter().cloned().collect();
|
||||
result.extend(self.carriers.iter().cloned());
|
||||
result
|
||||
}
|
||||
|
||||
/// exit PHI 対象
|
||||
#[allow(dead_code)] // Phase 30: will be used in F-3 generic lowering
|
||||
pub fn exit_phi_vars(&self) -> Vec<String> {
|
||||
self.exit_live.iter().cloned().collect()
|
||||
}
|
||||
|
||||
/// 変数を4分類
|
||||
#[cfg(test)]
|
||||
pub fn classify(&self, var_name: &str) -> LoopVarClass {
|
||||
if self.pinned.contains(var_name) {
|
||||
return LoopVarClass::Pinned;
|
||||
@ -105,20 +114,14 @@ impl LoopScopeShape {
|
||||
}
|
||||
}
|
||||
|
||||
/// 複数変数を一括分類
|
||||
pub fn classify_all(&self, var_names: &[String]) -> Vec<(String, LoopVarClass)> {
|
||||
var_names
|
||||
.iter()
|
||||
.map(|name| (name.clone(), self.classify(name)))
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// ループ終了時に live な変数集合を返す
|
||||
#[cfg(test)]
|
||||
pub fn get_exit_live(&self) -> &BTreeSet<String> {
|
||||
&self.exit_live
|
||||
}
|
||||
|
||||
/// 変数が required_blocks すべてで利用可能か判定
|
||||
#[cfg(test)]
|
||||
pub fn is_available_in_all(&self, var_name: &str, required_blocks: &[BasicBlockId]) -> bool {
|
||||
if let Some(def_blocks) = self.variable_definitions.get(var_name) {
|
||||
required_blocks.iter().all(|bid| def_blocks.contains(bid))
|
||||
|
||||
@ -108,7 +108,7 @@ impl LoopStructuralAnalysis {
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::mir::control_form::{ExitEdge, ExitKind, LoopId};
|
||||
use crate::mir::{BasicBlockId, ValueId};
|
||||
use crate::mir::BasicBlockId;
|
||||
use std::collections::{BTreeMap, BTreeSet};
|
||||
|
||||
fn make_single_exit_analysis() -> ExitAnalysis {
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
use super::*;
|
||||
use crate::mir::join_ir::lowering::loop_form_intake::LoopFormIntake;
|
||||
use crate::mir::phi_core::loop_exit_liveness::LoopExitLivenessBox;
|
||||
use crate::mir::phi_core::loop_var_classifier::{LoopVarClass, LoopVarClassBox};
|
||||
use super::shape::LoopVarClass;
|
||||
use crate::mir::{BasicBlockId, MirQuery, ValueId};
|
||||
use std::collections::{BTreeMap, BTreeSet};
|
||||
|
||||
@ -49,21 +48,12 @@ impl MirQuery for EmptyQuery {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_existing_boxes_basic() {
|
||||
fn test_from_loop_form_basic() {
|
||||
let loop_form = make_dummy_loop_form();
|
||||
let intake = make_dummy_intake();
|
||||
let var_classes = LoopVarClassBox::new();
|
||||
let exit_live_box = LoopExitLivenessBox::new();
|
||||
let query = EmptyQuery;
|
||||
|
||||
let scope = LoopScopeShape::from_existing_boxes(
|
||||
&loop_form,
|
||||
&intake,
|
||||
&var_classes,
|
||||
&exit_live_box,
|
||||
&query,
|
||||
None,
|
||||
);
|
||||
let scope = LoopScopeShape::from_loop_form(&loop_form, &intake, &query, None);
|
||||
|
||||
assert!(scope.is_some());
|
||||
let scope = scope.unwrap();
|
||||
@ -87,19 +77,9 @@ fn test_from_existing_boxes_basic() {
|
||||
fn test_needs_header_phi() {
|
||||
let loop_form = make_dummy_loop_form();
|
||||
let intake = make_dummy_intake();
|
||||
let var_classes = LoopVarClassBox::new();
|
||||
let exit_live_box = LoopExitLivenessBox::new();
|
||||
let query = EmptyQuery;
|
||||
|
||||
let scope = LoopScopeShape::from_existing_boxes(
|
||||
&loop_form,
|
||||
&intake,
|
||||
&var_classes,
|
||||
&exit_live_box,
|
||||
&query,
|
||||
None,
|
||||
)
|
||||
.unwrap();
|
||||
let scope = LoopScopeShape::from_loop_form(&loop_form, &intake, &query, None).unwrap();
|
||||
|
||||
assert!(scope.needs_header_phi("s"));
|
||||
assert!(scope.needs_header_phi("n"));
|
||||
@ -111,19 +91,9 @@ fn test_needs_header_phi() {
|
||||
fn test_needs_exit_phi() {
|
||||
let loop_form = make_dummy_loop_form();
|
||||
let intake = make_dummy_intake();
|
||||
let var_classes = LoopVarClassBox::new();
|
||||
let exit_live_box = LoopExitLivenessBox::new();
|
||||
let query = EmptyQuery;
|
||||
|
||||
let scope = LoopScopeShape::from_existing_boxes(
|
||||
&loop_form,
|
||||
&intake,
|
||||
&var_classes,
|
||||
&exit_live_box,
|
||||
&query,
|
||||
None,
|
||||
)
|
||||
.unwrap();
|
||||
let scope = LoopScopeShape::from_loop_form(&loop_form, &intake, &query, None).unwrap();
|
||||
|
||||
assert!(scope.needs_exit_phi("s"));
|
||||
assert!(scope.needs_exit_phi("n"));
|
||||
@ -134,19 +104,9 @@ fn test_needs_exit_phi() {
|
||||
fn test_ordered_accessors() {
|
||||
let loop_form = make_dummy_loop_form();
|
||||
let intake = make_dummy_intake();
|
||||
let var_classes = LoopVarClassBox::new();
|
||||
let exit_live_box = LoopExitLivenessBox::new();
|
||||
let query = EmptyQuery;
|
||||
|
||||
let scope = LoopScopeShape::from_existing_boxes(
|
||||
&loop_form,
|
||||
&intake,
|
||||
&var_classes,
|
||||
&exit_live_box,
|
||||
&query,
|
||||
None,
|
||||
)
|
||||
.unwrap();
|
||||
let scope = LoopScopeShape::from_loop_form(&loop_form, &intake, &query, None).unwrap();
|
||||
|
||||
let pinned = scope.pinned_ordered();
|
||||
assert_eq!(pinned.len(), 2);
|
||||
@ -197,19 +157,9 @@ fn test_block_ids_preserved() {
|
||||
};
|
||||
|
||||
let intake = make_dummy_intake();
|
||||
let var_classes = LoopVarClassBox::new();
|
||||
let exit_live_box = LoopExitLivenessBox::new();
|
||||
let query = EmptyQuery;
|
||||
|
||||
let scope = LoopScopeShape::from_existing_boxes(
|
||||
&loop_form,
|
||||
&intake,
|
||||
&var_classes,
|
||||
&exit_live_box,
|
||||
&query,
|
||||
None,
|
||||
)
|
||||
.unwrap();
|
||||
let scope = LoopScopeShape::from_loop_form(&loop_form, &intake, &query, None).unwrap();
|
||||
|
||||
assert_eq!(scope.header, BasicBlockId::new(200));
|
||||
assert_eq!(scope.body, BasicBlockId::new(300));
|
||||
@ -245,19 +195,9 @@ fn test_deterministic_order() {
|
||||
fn test_needs_phi_consistency() {
|
||||
let loop_form = make_dummy_loop_form();
|
||||
let intake = make_dummy_intake();
|
||||
let var_classes = LoopVarClassBox::new();
|
||||
let exit_live_box = LoopExitLivenessBox::new();
|
||||
let query = EmptyQuery;
|
||||
|
||||
let scope = LoopScopeShape::from_existing_boxes(
|
||||
&loop_form,
|
||||
&intake,
|
||||
&var_classes,
|
||||
&exit_live_box,
|
||||
&query,
|
||||
None,
|
||||
)
|
||||
.unwrap();
|
||||
let scope = LoopScopeShape::from_loop_form(&loop_form, &intake, &query, None).unwrap();
|
||||
|
||||
for var in &scope.pinned {
|
||||
assert!(
|
||||
@ -458,7 +398,7 @@ fn test_is_available_in_all_phase48_5_future() {
|
||||
assert!(!scope.is_available_in_all("unknown", &[BasicBlockId::new(3)]));
|
||||
}
|
||||
|
||||
/// Phase 48-4: from_existing_boxes で variable_definitions が埋まることを確認
|
||||
/// Phase 48-4: from_loop_form で variable_definitions が埋まることを確認
|
||||
#[test]
|
||||
fn test_variable_definitions_from_inspector() {
|
||||
let loop_form = make_dummy_loop_form();
|
||||
@ -481,19 +421,9 @@ fn test_variable_definitions_from_inspector() {
|
||||
(BasicBlockId::new(11), exit2_snap),
|
||||
];
|
||||
|
||||
let var_classes = LoopVarClassBox::new();
|
||||
let exit_live_box = LoopExitLivenessBox::new();
|
||||
let query = EmptyQuery;
|
||||
|
||||
let scope = LoopScopeShape::from_existing_boxes(
|
||||
&loop_form,
|
||||
&intake,
|
||||
&var_classes,
|
||||
&exit_live_box,
|
||||
&query,
|
||||
None,
|
||||
)
|
||||
.unwrap();
|
||||
let scope = LoopScopeShape::from_loop_form(&loop_form, &intake, &query, None).unwrap();
|
||||
|
||||
// s, n, i は両方の exit で利用可能 → is_available_in_all should be true
|
||||
assert!(scope.is_available_in_all("s", &[BasicBlockId::new(10), BasicBlockId::new(11)]));
|
||||
@ -532,19 +462,9 @@ fn test_variable_definitions_partial_availability() {
|
||||
(BasicBlockId::new(22), exit3_snap),
|
||||
];
|
||||
|
||||
let var_classes = LoopVarClassBox::new();
|
||||
let exit_live_box = LoopExitLivenessBox::new();
|
||||
let query = EmptyQuery;
|
||||
|
||||
let scope = LoopScopeShape::from_existing_boxes(
|
||||
&loop_form,
|
||||
&intake,
|
||||
&var_classes,
|
||||
&exit_live_box,
|
||||
&query,
|
||||
None,
|
||||
)
|
||||
.unwrap();
|
||||
let scope = LoopScopeShape::from_loop_form(&loop_form, &intake, &query, None).unwrap();
|
||||
|
||||
// s は全 exit で利用可能
|
||||
assert!(scope.is_available_in_all(
|
||||
|
||||
@ -98,8 +98,8 @@ impl LoopToJoinLowerer {
|
||||
let query = MirQueryBox::new(func);
|
||||
|
||||
// Step 2: LoopFormIntake を構築
|
||||
// Phase 48-2: intake_loop_form は空の var_classes を使用(将来は from_loop_form に統合)
|
||||
let intake = intake_loop_form(loop_form, &Default::default(), &query, func)?;
|
||||
// Phase 70-2: var_classes 引数削除完了(Trio 依存ゼロ)
|
||||
let intake = intake_loop_form(loop_form, &query, func)?;
|
||||
|
||||
// Step 3: LoopScopeShape を構築
|
||||
// Phase 48-2: from_loop_form() で Trio を内部化(LoopExitLivenessBox 依存削除)
|
||||
|
||||
Reference in New Issue
Block a user