Files
hakorune/src/mir/join_ir/lowering/if_merge.rs
nyash-codex c2f524bb26 refactor(joinir): Phase 185 code cleanup - extract shared function, remove dead code
- Extract infer_type_from_mir_pattern() to common.rs (was duplicated in if_select.rs & if_merge.rs)
- Remove unused JOINIR_HEADER_BYPASS_TARGETS and is_joinir_header_bypass_target() from loopform_builder.rs
- Warnings reduced: 13 → 11

Lines removed: ~45 (duplicate function + dead code)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-04 22:33:56 +09:00

295 lines
9.5 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-7: If/Else の IfMerge 命令への lowering
//!
//! 複数変数を merge する if/else を JoinInst::IfMerge に変換する。
//!
//! Phase 33-7 制約:
//! - return パターンのみcontinuation は Phase 33-8
//! - k_next=None のみ
//!
//! ## 責務分離Phase 33-9.1
//!
//! **IfMergeLowerer の責務**:
//! - 複数変数を持つ if/else を IfMerge 命令に変換する
//!
//! **非責務**:
//! - Loop の PHI には触らないLoop lowering の責務)
use crate::mir::join_ir::{JoinInst, MergePair};
use crate::mir::{BasicBlockId, MirFunction, MirInstruction, MirType, ValueId};
use std::collections::HashSet;
// Phase 61-1: If-in-loop context support
use super::if_phi_context::IfPhiContext;
pub struct IfMergeLowerer {
debug_level: u8,
// Phase 61-1: If-in-loop context (None = Pure If)
#[allow(dead_code)]
context: Option<IfPhiContext>,
}
/// 検出された IfMerge パターン情報
#[derive(Debug, Clone)]
struct IfMergePattern {
cond: ValueId,
merge_pairs: Vec<MergePair>,
}
/// Branch 命令の情報
#[derive(Debug, Clone)]
struct IfBranch {
cond: ValueId,
then_block: BasicBlockId,
else_block: BasicBlockId,
}
impl IfMergeLowerer {
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 = IfMergeLowerer::with_context(debug_level, context);
/// ```
pub fn with_context(debug_level: u8, context: IfPhiContext) -> Self {
Self {
debug_level,
context: Some(context),
}
}
/// if/else が IfMerge に lowering できるかチェック
pub fn can_lower_to_if_merge(&self, func: &MirFunction, if_block_id: BasicBlockId) -> bool {
self.find_if_merge_pattern(func, if_block_id).is_some()
}
/// if/else を IfMerge に変換
pub fn lower_if_to_if_merge(
&self,
func: &MirFunction,
if_block_id: BasicBlockId,
) -> Option<JoinInst> {
let pattern = self.find_if_merge_pattern(func, if_block_id)?;
// Phase 33-8: Level 1 - Basic lowering info
if self.debug_level >= 1 {
eprintln!(
"[IfMergeLowerer] ✅ lowering to IfMerge with {} merge pairs",
pattern.merge_pairs.len()
);
}
// Phase 33-8: Level 3 - Full merge details
if self.debug_level >= 3 {
eprintln!("[IfMergeLowerer] cond: {:?}", pattern.cond);
for (i, pair) in pattern.merge_pairs.iter().enumerate() {
eprintln!(
"[IfMergeLowerer] pair[{}]: dst={:?}, then={:?}, else={:?}",
i, pair.dst, pair.then_val, pair.else_val
);
}
}
// IfMerge 命令を生成
Some(JoinInst::IfMerge {
cond: pattern.cond,
merges: pattern.merge_pairs,
k_next: None, // Phase 33-7 制約
})
}
/// MIR 関数から IfMerge パターンを探す
fn find_if_merge_pattern(
&self,
func: &MirFunction,
block_id: BasicBlockId,
) -> Option<IfMergePattern> {
// 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)?;
// 3. Phase 33-7 制約: return パターンのみ
// 両方のブロックが Return で終わる必要がある
let is_then_return = matches!(
then_block.terminator.as_ref(),
Some(MirInstruction::Return { .. })
);
let is_else_return = matches!(
else_block.terminator.as_ref(),
Some(MirInstruction::Return { .. })
);
if !is_then_return || !is_else_return {
// Phase 33-8: Level 2 - Pattern matching details
if self.debug_level >= 2 {
eprintln!(
"[IfMergeLowerer] ❌ not return pattern (then={}, else={})",
is_then_return, is_else_return
);
}
return None;
}
// 4. then/else で書き込まれる変数を抽出
let then_writes = self.extract_written_vars(&then_block.instructions);
let else_writes = self.extract_written_vars(&else_block.instructions);
// Phase 33-8: Level 3 - Full variable dump
if self.debug_level >= 3 {
eprintln!(
"[IfMergeLowerer] then writes: {:?}, else writes: {:?}",
then_writes, else_writes
);
}
// 5. 両方で書き込まれる変数(共通集合)を抽出
let common_writes: HashSet<_> = then_writes.intersection(&else_writes).copied().collect();
if common_writes.is_empty() {
// Phase 33-8: Level 2 - Pattern matching details
if self.debug_level >= 2 {
eprintln!("[IfMergeLowerer] ❌ no common writes found");
}
return None;
}
// 6. 各共通変数について MergePair を生成
let mut merge_pairs = Vec::new();
for &dst in &common_writes {
// then ブロックで dst に書き込まれる値を探す
let then_val = self.find_written_value(&then_block.instructions, dst)?;
// else ブロックで dst に書き込まれる値を探す
let else_val = self.find_written_value(&else_block.instructions, dst)?;
// Phase 64-2: then_val / else_val から型ヒント推論
let type_hint = infer_type_from_mir_pattern(func, then_val)
.or_else(|| infer_type_from_mir_pattern(func, else_val));
merge_pairs.push(MergePair {
dst,
then_val,
else_val,
type_hint, // Phase 64-2: Const 命令から型推論
});
}
if merge_pairs.is_empty() {
return None;
}
// 7. MergePair を dst でソートして決定的に
merge_pairs.sort_by_key(|pair| pair.dst.0);
Some(IfMergePattern {
cond: branch.cond,
merge_pairs,
})
}
/// 命令列から書き込まれる変数集合を抽出
fn extract_written_vars(&self, instructions: &[MirInstruction]) -> HashSet<ValueId> {
let mut writes = HashSet::new();
for inst in instructions {
match inst {
MirInstruction::Copy { dst, .. }
| MirInstruction::Const { dst, .. }
| MirInstruction::BinOp { dst, .. }
| MirInstruction::Compare { dst, .. } => {
writes.insert(*dst);
}
MirInstruction::Call { dst: Some(dst), .. }
| MirInstruction::BoxCall { dst: Some(dst), .. } => {
writes.insert(*dst);
}
_ => {}
}
}
writes
}
/// 命令列から dst に書き込まれる値を探す(最後の書き込み)
fn find_written_value(&self, instructions: &[MirInstruction], dst: ValueId) -> Option<ValueId> {
// 逆順で探索して最後の書き込みを見つける
for inst in instructions.iter().rev() {
match inst {
MirInstruction::Copy { dst: inst_dst, src } if *inst_dst == dst => {
return Some(*src);
}
MirInstruction::Const { dst: inst_dst, .. }
| MirInstruction::BinOp { dst: inst_dst, .. }
| MirInstruction::Compare { dst: inst_dst, .. }
| MirInstruction::Call {
dst: Some(inst_dst),
..
}
| MirInstruction::BoxCall {
dst: Some(inst_dst),
..
} if *inst_dst == dst => {
// dst 自身が書き込まれる場合は dst を返す
return Some(dst);
}
_ => {}
}
}
None
}
}
// Phase 185: infer_type_from_mir_pattern() moved to common.rs
use super::common::infer_type_from_mir_pattern;
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_if_merge_lowerer_creation() {
let lowerer = IfMergeLowerer::new(0);
assert_eq!(lowerer.debug_level, 0);
let lowerer_compat = IfMergeLowerer::with_debug(true);
assert_eq!(lowerer_compat.debug_level, 1);
}
}