Files
hakorune/src/mir/join_ir/lowering/if_select.rs
nyash-codex d7805e5974 feat(joinir): Phase 213-2 Step 2-2 & 2-3 Data structure extensions
Extended PatternPipelineContext and CarrierUpdateInfo for Pattern 3 AST-based generalization.

Changes:
1. PatternPipelineContext:
   - Added loop_condition: Option<ASTNode>
   - Added loop_body: Option<Vec<ASTNode>>
   - Added loop_update_summary: Option<LoopUpdateSummary>
   - Updated build_pattern_context() for Pattern 3

2. CarrierUpdateInfo:
   - Added then_expr: Option<ASTNode>
   - Added else_expr: Option<ASTNode>
   - Updated analyze_loop_updates() with None defaults

Status: Phase 213-2 Steps 2-2 & 2-3 complete
Next: Create Pattern3IfAnalyzer to extract if statement and populate update summary
2025-12-10 00:01:53 +09:00

377 lines
13 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//! 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<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
#[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<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);
// 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<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
// - 実用MIRconst + 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),
})
}
}
// Phase 185: infer_type_from_mir_pattern() moved to common.rs
use super::common::infer_type_from_mir_pattern;