## リファクタリング内容
### ファイル構造変更
- `src/mir/loop_builder.rs` (1515行) 削除
- `src/mir/loop_builder/` ディレクトリ新設(6ファイル、1529行)
### 新規モジュール構成
1. **mod.rs** (6,293行 → 実際は約150行)
- モジュール定義とre-export
- LoopBuilder構造体定義
2. **loop_form.rs** (25,988行 → 実際は約650行)
- メインループlowering pipeline
- デバッグ/実験フラグ集約
3. **if_lowering.rs** (15,600行 → 実際は約390行)
- In-loop if lowering with JoinIR/PHI bridge
- **Phase 61-2コード完全保持**:
- JoinIR dry-run検証モード
- PhiSpec計算とA/B比較
4. **phi_ops.rs** (12,844行 → 実際は約320行)
- PHI emit helpers
- LoopFormOps/PhiBuilderOps impls
5. **control.rs** (4,261行 → 実際は約107行)
- break/continue capture
- predecessor bookkeeping
6. **statements.rs** (1,673行 → 実際は約42行)
- loop-body statement lowering entry point
7. **README.md** (752行 → 実際は約19行)
- モジュール責務とサブモジュール説明
### 設計原則
- **責務分離**: CFG構築/PHI生成/制御フロー/文処理を分離
- **Phase 61-2保持**: if_lowering.rsにJoinIR dry-run完全移行
- **phi_core委譲**: PHI構築ロジックは`phi_core`に委譲
## テスト結果
- Phase 61-2テスト: ✅ 2/2 PASS(dry-runフラグ、PhiSpec)
- loopformテスト: ✅ 14/14 PASS(退行なし)
- ビルド: ✅ 成功(エラー0件)
## 統計
- **純削減**: -1,521行(25ファイル変更)
- **loop_builder**: 1515行 → 1529行(+14行、6ファイル化)
- **可読性**: 巨大単一ファイル → 責務別モジュール
## ChatGPT設計・Claude確認
大規模リファクタリングをChatGPTが実施、Claudeが検証完了。
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
367 lines
12 KiB
Rust
367 lines
12 KiB
Rust
//! Phase 33: If/Else の Select 命令への lowering
|
||
//!
|
||
//! 最小の if/else(副作用なし、単純な値選択)を JoinInst::Select に変換する。
|
||
//!
|
||
//! ## 責務分離(Phase 33-9.1)
|
||
//!
|
||
//! **IfSelectLowerer の責務**:
|
||
//! - 単純 if/else(副作用なし、単一変数)を Select 命令に変換する
|
||
//!
|
||
//! **非責務**:
|
||
//! - Loop の PHI には触らない(Loop lowering の責務)
|
||
|
||
use crate::mir::join_ir::JoinInst;
|
||
use crate::mir::{BasicBlockId, MirFunction, MirInstruction, ValueId};
|
||
|
||
// Phase 61-1: If-in-loop context support
|
||
use super::if_phi_context::IfPhiContext;
|
||
|
||
pub struct IfSelectLowerer {
|
||
debug_level: u8,
|
||
// Phase 61-1: If-in-loop context (None = Pure If)
|
||
#[allow(dead_code)]
|
||
context: Option<IfPhiContext>,
|
||
}
|
||
|
||
/// If/Else パターンの分類
|
||
#[derive(Debug, Clone, Copy)]
|
||
enum IfPatternType {
|
||
/// Simple pattern: if cond { return 1 } else { return 2 }
|
||
Simple,
|
||
/// Local pattern: if cond { x = a } else { x = b }; return x
|
||
Local,
|
||
}
|
||
|
||
/// 検出された If/Else パターン情報
|
||
#[derive(Debug, Clone)]
|
||
struct IfPattern {
|
||
pattern_type: IfPatternType,
|
||
cond: ValueId,
|
||
then_val: ValueId,
|
||
else_val: ValueId,
|
||
dst: Option<ValueId>,
|
||
}
|
||
|
||
/// Branch 命令の情報
|
||
#[derive(Debug, Clone)]
|
||
struct IfBranch {
|
||
cond: ValueId,
|
||
then_block: BasicBlockId,
|
||
else_block: BasicBlockId,
|
||
}
|
||
|
||
impl IfSelectLowerer {
|
||
pub fn new(debug_level: u8) -> Self {
|
||
Self {
|
||
debug_level,
|
||
context: None, // Phase 61-1: デフォルトは Pure If
|
||
}
|
||
}
|
||
|
||
/// Phase 33-8: debug-level backward compat wrapper
|
||
pub fn with_debug(debug: bool) -> Self {
|
||
Self {
|
||
debug_level: if debug { 1 } else { 0 },
|
||
context: None, // Phase 61-1: デフォルトは Pure If
|
||
}
|
||
}
|
||
|
||
/// Phase 61-1: If-in-loop 用コンストラクタ
|
||
///
|
||
/// # Arguments
|
||
///
|
||
/// * `debug_level` - デバッグログレベル (0-3)
|
||
/// * `context` - If-in-loop コンテキスト(carrier_names 情報を含む)
|
||
///
|
||
/// # Example
|
||
///
|
||
/// ```ignore
|
||
/// let context = IfPhiContext::for_loop_body(carrier_names);
|
||
/// let lowerer = IfSelectLowerer::with_context(debug_level, context);
|
||
/// ```
|
||
pub fn with_context(debug_level: u8, context: IfPhiContext) -> Self {
|
||
Self {
|
||
debug_level,
|
||
context: Some(context),
|
||
}
|
||
}
|
||
|
||
/// if/else が Select に lowering できるかチェック
|
||
pub fn can_lower_to_select(&self, func: &MirFunction, if_block_id: BasicBlockId) -> bool {
|
||
self.find_if_pattern(func, if_block_id).is_some()
|
||
}
|
||
|
||
/// if/else を Select に変換
|
||
pub fn lower_if_to_select(
|
||
&self,
|
||
func: &MirFunction,
|
||
if_block_id: BasicBlockId,
|
||
) -> Option<JoinInst> {
|
||
let pattern = self.find_if_pattern(func, if_block_id)?;
|
||
|
||
// Phase 33-8: Level 1 - Basic lowering info
|
||
if self.debug_level >= 1 {
|
||
eprintln!(
|
||
"[IfSelectLowerer] ✅ lowering {:?} pattern to Select",
|
||
pattern.pattern_type
|
||
);
|
||
}
|
||
|
||
// Phase 33-8: Level 3 - Full pattern details
|
||
if self.debug_level >= 3 {
|
||
eprintln!("[IfSelectLowerer] cond: {:?}", pattern.cond);
|
||
eprintln!("[IfSelectLowerer] then_val: {:?}", pattern.then_val);
|
||
eprintln!("[IfSelectLowerer] else_val: {:?}", pattern.else_val);
|
||
eprintln!("[IfSelectLowerer] dst: {:?}", pattern.dst);
|
||
}
|
||
|
||
// Select 命令を生成
|
||
let dst = pattern.dst.unwrap_or(pattern.then_val);
|
||
|
||
Some(JoinInst::Select {
|
||
dst,
|
||
cond: pattern.cond,
|
||
then_val: pattern.then_val,
|
||
else_val: pattern.else_val,
|
||
})
|
||
}
|
||
|
||
/// MIR 関数から if/else パターンを探す
|
||
fn find_if_pattern(&self, func: &MirFunction, block_id: BasicBlockId) -> Option<IfPattern> {
|
||
// 1. Block が Branch 命令で終わっているか確認
|
||
let block = func.blocks.get(&block_id)?;
|
||
let branch = match block.terminator.as_ref()? {
|
||
MirInstruction::Branch {
|
||
condition,
|
||
then_bb,
|
||
else_bb,
|
||
} => IfBranch {
|
||
cond: *condition,
|
||
then_block: *then_bb,
|
||
else_block: *else_bb,
|
||
},
|
||
_ => return None,
|
||
};
|
||
|
||
// 2. then/else ブロックの構造を確認
|
||
let then_block = func.blocks.get(&branch.then_block)?;
|
||
let else_block = func.blocks.get(&branch.else_block)?;
|
||
|
||
// Phase 33-10: PHI早期チェック(パターンマッチング前)
|
||
// JoinIRは「PHI生成器」であり「PHI変換器」ではない
|
||
// then/elseがJumpで終わる場合、merge blockにPHI命令があるか早期確認
|
||
if let Some(merge_block_id) =
|
||
self.get_merge_block_if_jump_pattern(&branch, then_block, else_block)
|
||
{
|
||
let merge_block = func.blocks.get(&merge_block_id)?;
|
||
if merge_block
|
||
.instructions
|
||
.iter()
|
||
.any(|inst| matches!(inst, MirInstruction::Phi { .. }))
|
||
{
|
||
if self.debug_level >= 2 {
|
||
eprintln!("[IfSelectLowerer] ⏭️ PHI already exists in merge block, skipping");
|
||
}
|
||
return None;
|
||
}
|
||
}
|
||
|
||
// 3. simple パターンのチェック
|
||
if let Some(pattern) = self.try_match_simple_pattern(&branch, then_block, else_block) {
|
||
// Phase 33-8: Level 2 - Pattern matching details
|
||
if self.debug_level >= 2 {
|
||
eprintln!("[IfSelectLowerer] ✅ matched simple pattern");
|
||
}
|
||
return Some(pattern);
|
||
}
|
||
|
||
// 4. local パターンのチェック
|
||
if let Some(pattern) = self.try_match_local_pattern(func, &branch, then_block, else_block) {
|
||
// Phase 33-8: Level 2 - Pattern matching details
|
||
if self.debug_level >= 2 {
|
||
eprintln!("[IfSelectLowerer] ✅ matched local pattern");
|
||
}
|
||
return Some(pattern);
|
||
}
|
||
|
||
// Phase 33-8: Level 2 - Pattern matching details
|
||
if self.debug_level >= 2 {
|
||
eprintln!("[IfSelectLowerer] ❌ no pattern matched");
|
||
}
|
||
None
|
||
}
|
||
|
||
/// simple パターン: if cond { return 1 } else { return 2 }
|
||
///
|
||
/// Phase 33-9.2: 実用MIR対応 - 副作用なし命令(Const/Copy)を許容
|
||
/// - 旧: Return のみ(instructions empty)
|
||
/// - 新: Const/Copy → Return を許容(実MIRパターン)
|
||
fn try_match_simple_pattern(
|
||
&self,
|
||
branch: &IfBranch,
|
||
then_block: &crate::mir::BasicBlock,
|
||
else_block: &crate::mir::BasicBlock,
|
||
) -> Option<IfPattern> {
|
||
// then ブロックが Return だけか確認
|
||
let then_val = match then_block.terminator.as_ref()? {
|
||
MirInstruction::Return { value: Some(v) } => *v,
|
||
_ => return None,
|
||
};
|
||
|
||
// else ブロックが Return だけか確認
|
||
let else_val = match else_block.terminator.as_ref()? {
|
||
MirInstruction::Return { value: Some(v) } => *v,
|
||
_ => return None,
|
||
};
|
||
|
||
// Phase 33-9.2: 副作用なし命令(Const/Copy)のみを許容
|
||
// - ユニットテスト(empty)も通過(空配列 → all() = true)
|
||
// - 実用MIR(const + ret)も通過
|
||
if !self.is_side_effect_free(&then_block.instructions)
|
||
|| !self.is_side_effect_free(&else_block.instructions)
|
||
{
|
||
return None;
|
||
}
|
||
|
||
Some(IfPattern {
|
||
pattern_type: IfPatternType::Simple,
|
||
cond: branch.cond,
|
||
then_val,
|
||
else_val,
|
||
dst: None,
|
||
})
|
||
}
|
||
|
||
/// Phase 33-9.2: 副作用なし命令判定ヘルパー
|
||
///
|
||
/// Const/Copy のみを許容(分岐・call・書き込み等は除外)
|
||
fn is_side_effect_free(&self, instructions: &[MirInstruction]) -> bool {
|
||
instructions.iter().all(|inst| {
|
||
matches!(
|
||
inst,
|
||
MirInstruction::Const { .. } | MirInstruction::Copy { .. }
|
||
)
|
||
})
|
||
}
|
||
|
||
/// Phase 33-10: Jump pattern 検出ヘルパー
|
||
///
|
||
/// then/else 両方が Jump で終わり、同じ merge block に飛んでいる場合、
|
||
/// その merge block IDを返す
|
||
fn get_merge_block_if_jump_pattern(
|
||
&self,
|
||
_branch: &IfBranch,
|
||
then_block: &crate::mir::BasicBlock,
|
||
else_block: &crate::mir::BasicBlock,
|
||
) -> Option<BasicBlockId> {
|
||
// then が Jump で終わるか確認
|
||
let then_target = match then_block.terminator.as_ref()? {
|
||
MirInstruction::Jump { target } => *target,
|
||
_ => return None,
|
||
};
|
||
|
||
// else が Jump で終わるか確認
|
||
let else_target = match else_block.terminator.as_ref()? {
|
||
MirInstruction::Jump { target } => *target,
|
||
_ => return None,
|
||
};
|
||
|
||
// 両方が同じ merge block に飛んでいるか確認
|
||
if then_target == else_target {
|
||
Some(then_target)
|
||
} else {
|
||
None
|
||
}
|
||
}
|
||
|
||
/// local パターン: if cond { x = a } else { x = b }; return x
|
||
///
|
||
/// Phase 33-10: 実用MIR対応 - Const命令を許容
|
||
/// - 旧: Copy命令のみ(ユニットテスト想定)
|
||
/// - 新: Const/Copy命令を許容(実MIR対応、Simple patternと同じ修正)
|
||
fn try_match_local_pattern(
|
||
&self,
|
||
func: &MirFunction,
|
||
branch: &IfBranch,
|
||
then_block: &crate::mir::BasicBlock,
|
||
else_block: &crate::mir::BasicBlock,
|
||
) -> Option<IfPattern> {
|
||
// Phase 33-10: 副作用なし命令のみを許容
|
||
if !self.is_side_effect_free(&then_block.instructions) {
|
||
return None;
|
||
}
|
||
|
||
// then ブロックの最後の値を取得
|
||
// Phase 33-10: Const命令も許容(実MIR対応)
|
||
let (dst_then, val_then) = if then_block.instructions.len() == 1 {
|
||
match &then_block.instructions[0] {
|
||
MirInstruction::Copy { dst, src } => (*dst, *src),
|
||
MirInstruction::Const { dst, .. } => (*dst, *dst), // Constの場合、dst自身が値
|
||
_ => return None,
|
||
}
|
||
} else {
|
||
return None;
|
||
};
|
||
|
||
// then ブロックが Jump で終わるか確認
|
||
let merge_block_id = match then_block.terminator.as_ref()? {
|
||
MirInstruction::Jump { target } => *target,
|
||
_ => return None,
|
||
};
|
||
|
||
// Phase 33-10: else ブロックも副作用なし命令のみを許容
|
||
if !self.is_side_effect_free(&else_block.instructions) {
|
||
return None;
|
||
}
|
||
|
||
// else ブロックの最後の値を取得
|
||
let (dst_else, val_else) = if else_block.instructions.len() == 1 {
|
||
match &else_block.instructions[0] {
|
||
MirInstruction::Copy { dst, src } => (*dst, *src),
|
||
MirInstruction::Const { dst, .. } => (*dst, *dst), // Constの場合、dst自身が値
|
||
_ => return None,
|
||
}
|
||
} else {
|
||
return None;
|
||
};
|
||
|
||
// 代入先が同じ変数か確認
|
||
if dst_then != dst_else {
|
||
return None;
|
||
}
|
||
|
||
// else ブロックも同じ merge ブロックに Jump するか確認
|
||
let else_merge = match else_block.terminator.as_ref()? {
|
||
MirInstruction::Jump { target } => *target,
|
||
_ => return None,
|
||
};
|
||
|
||
if merge_block_id != else_merge {
|
||
return None;
|
||
}
|
||
|
||
// merge ブロックが「return dst」だけか確認
|
||
let merge_block = func.blocks.get(&merge_block_id)?;
|
||
// Phase 33-10: PHIチェックは find_if_pattern() で早期実行済み
|
||
|
||
match merge_block.terminator.as_ref()? {
|
||
MirInstruction::Return { value: Some(v) } if *v == dst_then => {
|
||
// OK
|
||
}
|
||
_ => return None,
|
||
}
|
||
|
||
if !merge_block.instructions.is_empty() {
|
||
return None;
|
||
}
|
||
|
||
Some(IfPattern {
|
||
pattern_type: IfPatternType::Local,
|
||
cond: branch.cond,
|
||
then_val: val_then,
|
||
else_val: val_else,
|
||
dst: Some(dst_then),
|
||
})
|
||
}
|
||
}
|