2025-11-27 02:58:38 +09:00
|
|
|
|
//! Phase 33: If/Else の Select 命令への lowering
|
|
|
|
|
|
//!
|
|
|
|
|
|
//! 最小の if/else(副作用なし、単純な値選択)を JoinInst::Select に変換する。
|
2025-11-27 10:58:56 +09:00
|
|
|
|
//!
|
|
|
|
|
|
//! ## 責務分離(Phase 33-9.1)
|
|
|
|
|
|
//!
|
|
|
|
|
|
//! **IfSelectLowerer の責務**:
|
|
|
|
|
|
//! - 単純 if/else(副作用なし、単一変数)を Select 命令に変換する
|
|
|
|
|
|
//!
|
|
|
|
|
|
//! **非責務**:
|
|
|
|
|
|
//! - Loop の PHI には触らない(Loop lowering の責務)
|
2025-11-27 02:58:38 +09:00
|
|
|
|
|
|
|
|
|
|
use crate::mir::join_ir::JoinInst;
|
2025-11-27 03:28:32 +09:00
|
|
|
|
use crate::mir::{BasicBlockId, MirFunction, MirInstruction, ValueId};
|
2025-11-27 02:58:38 +09:00
|
|
|
|
|
|
|
|
|
|
pub struct IfSelectLowerer {
|
2025-11-27 09:30:54 +09:00
|
|
|
|
debug_level: u8,
|
2025-11-27 02:58:38 +09:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-27 03:28:32 +09:00
|
|
|
|
/// 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,
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-27 02:58:38 +09:00
|
|
|
|
impl IfSelectLowerer {
|
2025-11-27 09:30:54 +09:00
|
|
|
|
pub fn new(debug_level: u8) -> Self {
|
|
|
|
|
|
Self { debug_level }
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// Phase 33-8: debug-level backward compat wrapper
|
|
|
|
|
|
pub fn with_debug(debug: bool) -> Self {
|
|
|
|
|
|
Self { debug_level: if debug { 1 } else { 0 } }
|
2025-11-27 02:58:38 +09:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// if/else が Select に lowering できるかチェック
|
2025-11-27 03:28:32 +09:00
|
|
|
|
pub fn can_lower_to_select(&self, func: &MirFunction, if_block_id: BasicBlockId) -> bool {
|
|
|
|
|
|
self.find_if_pattern(func, if_block_id).is_some()
|
2025-11-27 02:58:38 +09:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// if/else を Select に変換
|
|
|
|
|
|
pub fn lower_if_to_select(
|
|
|
|
|
|
&self,
|
2025-11-27 03:28:32 +09:00
|
|
|
|
func: &MirFunction,
|
|
|
|
|
|
if_block_id: BasicBlockId,
|
2025-11-27 02:58:38 +09:00
|
|
|
|
) -> Option<JoinInst> {
|
2025-11-27 03:28:32 +09:00
|
|
|
|
let pattern = self.find_if_pattern(func, if_block_id)?;
|
|
|
|
|
|
|
2025-11-27 09:30:54 +09:00
|
|
|
|
// Phase 33-8: Level 1 - Basic lowering info
|
|
|
|
|
|
if self.debug_level >= 1 {
|
2025-11-27 03:28:32 +09:00
|
|
|
|
eprintln!(
|
2025-11-27 09:30:54 +09:00
|
|
|
|
"[IfSelectLowerer] ✅ lowering {:?} pattern to Select",
|
2025-11-27 03:28:32 +09:00
|
|
|
|
pattern.pattern_type
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-27 09:30:54 +09:00
|
|
|
|
// 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);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-27 03:28:32 +09:00
|
|
|
|
// 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)?;
|
|
|
|
|
|
|
2025-11-27 17:05:46 +09:00
|
|
|
|
// 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;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-27 03:28:32 +09:00
|
|
|
|
// 3. simple パターンのチェック
|
|
|
|
|
|
if let Some(pattern) = self.try_match_simple_pattern(&branch, then_block, else_block) {
|
2025-11-27 09:30:54 +09:00
|
|
|
|
// Phase 33-8: Level 2 - Pattern matching details
|
|
|
|
|
|
if self.debug_level >= 2 {
|
|
|
|
|
|
eprintln!("[IfSelectLowerer] ✅ matched simple pattern");
|
2025-11-27 03:28:32 +09:00
|
|
|
|
}
|
|
|
|
|
|
return Some(pattern);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 4. local パターンのチェック
|
|
|
|
|
|
if let Some(pattern) = self.try_match_local_pattern(func, &branch, then_block, else_block)
|
|
|
|
|
|
{
|
2025-11-27 09:30:54 +09:00
|
|
|
|
// Phase 33-8: Level 2 - Pattern matching details
|
|
|
|
|
|
if self.debug_level >= 2 {
|
|
|
|
|
|
eprintln!("[IfSelectLowerer] ✅ matched local pattern");
|
2025-11-27 03:28:32 +09:00
|
|
|
|
}
|
|
|
|
|
|
return Some(pattern);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-27 09:30:54 +09:00
|
|
|
|
// Phase 33-8: Level 2 - Pattern matching details
|
|
|
|
|
|
if self.debug_level >= 2 {
|
|
|
|
|
|
eprintln!("[IfSelectLowerer] ❌ no pattern matched");
|
2025-11-27 02:58:38 +09:00
|
|
|
|
}
|
|
|
|
|
|
None
|
|
|
|
|
|
}
|
2025-11-27 03:28:32 +09:00
|
|
|
|
|
|
|
|
|
|
/// simple パターン: if cond { return 1 } else { return 2 }
|
2025-11-27 17:05:46 +09:00
|
|
|
|
///
|
|
|
|
|
|
/// Phase 33-9.2: 実用MIR対応 - 副作用なし命令(Const/Copy)を許容
|
|
|
|
|
|
/// - 旧: Return のみ(instructions empty)
|
|
|
|
|
|
/// - 新: Const/Copy → Return を許容(実MIRパターン)
|
2025-11-27 03:28:32 +09:00
|
|
|
|
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,
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2025-11-27 17:05:46 +09:00
|
|
|
|
// 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)
|
|
|
|
|
|
{
|
2025-11-27 03:28:32 +09:00
|
|
|
|
return None;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Some(IfPattern {
|
|
|
|
|
|
pattern_type: IfPatternType::Simple,
|
|
|
|
|
|
cond: branch.cond,
|
|
|
|
|
|
then_val,
|
|
|
|
|
|
else_val,
|
|
|
|
|
|
dst: None,
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-27 17:05:46 +09:00
|
|
|
|
/// 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
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-27 03:28:32 +09:00
|
|
|
|
/// local パターン: if cond { x = a } else { x = b }; return x
|
2025-11-27 17:05:46 +09:00
|
|
|
|
///
|
|
|
|
|
|
/// Phase 33-10: 実用MIR対応 - Const命令を許容
|
|
|
|
|
|
/// - 旧: Copy命令のみ(ユニットテスト想定)
|
|
|
|
|
|
/// - 新: Const/Copy命令を許容(実MIR対応、Simple patternと同じ修正)
|
2025-11-27 03:28:32 +09:00
|
|
|
|
fn try_match_local_pattern(
|
|
|
|
|
|
&self,
|
|
|
|
|
|
func: &MirFunction,
|
|
|
|
|
|
branch: &IfBranch,
|
|
|
|
|
|
then_block: &crate::mir::BasicBlock,
|
|
|
|
|
|
else_block: &crate::mir::BasicBlock,
|
|
|
|
|
|
) -> Option<IfPattern> {
|
2025-11-27 17:05:46 +09:00
|
|
|
|
// Phase 33-10: 副作用なし命令のみを許容
|
|
|
|
|
|
if !self.is_side_effect_free(&then_block.instructions) {
|
2025-11-27 03:28:32 +09:00
|
|
|
|
return None;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-27 17:05:46 +09:00
|
|
|
|
// 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;
|
2025-11-27 03:28:32 +09:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// then ブロックが Jump で終わるか確認
|
|
|
|
|
|
let merge_block_id = match then_block.terminator.as_ref()? {
|
|
|
|
|
|
MirInstruction::Jump { target } => *target,
|
|
|
|
|
|
_ => return None,
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2025-11-27 17:05:46 +09:00
|
|
|
|
// Phase 33-10: else ブロックも副作用なし命令のみを許容
|
|
|
|
|
|
if !self.is_side_effect_free(&else_block.instructions) {
|
2025-11-27 03:28:32 +09:00
|
|
|
|
return None;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-11-27 17:05:46 +09:00
|
|
|
|
// 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;
|
2025-11-27 03:28:32 +09:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 代入先が同じ変数か確認
|
|
|
|
|
|
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)?;
|
2025-11-27 17:05:46 +09:00
|
|
|
|
// Phase 33-10: PHIチェックは find_if_pattern() で早期実行済み
|
|
|
|
|
|
|
2025-11-27 03:28:32 +09:00
|
|
|
|
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),
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
2025-11-27 02:58:38 +09:00
|
|
|
|
}
|