//! 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 63-2: Type hint inference from MIR // 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, } /// 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, } /// 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 #[allow(dead_code)] 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 { 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); // Phase 63-2: MIR の Const 命令から型ヒントを推論 let type_hint = infer_type_from_mir_pattern(func, pattern.then_val) .or_else(|| infer_type_from_mir_pattern(func, pattern.else_val)); Some(JoinInst::Select { dst, cond: pattern.cond, then_val: pattern.then_val, else_val: pattern.else_val, type_hint, // Phase 63-2: Const 命令から推論した型(Integer/Bool/String など) }) } /// MIR 関数から if/else パターンを探す fn find_if_pattern(&self, func: &MirFunction, block_id: BasicBlockId) -> Option { // 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 { // 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 { // 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 { // 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), }) } } // Phase 185: infer_type_from_mir_pattern() moved to common.rs use super::common::infer_type_from_mir_pattern;