Files
hakorune/src/mir/builder/control_flow/joinir/merge/mod.rs
nyash-codex eabef39748 feat(joinir/refactor): Phase 33-10-P1 ExitMetaCollector Box modularization
Box theory refactoring: Extract exit_bindings construction logic from
pattern lowerers into focused, reusable ExitMetaCollector Box.

**Changes**:
1. Created meta_collector.rs (+102 lines):
   - ExitMetaCollector::collect() builds exit_bindings from ExitMeta
   - Pure function (no side effects)
   - Reusable by all pattern lowerers

2. Updated pattern2_with_break.rs (-20 lines):
   - Use ExitMetaCollector::collect() instead of inline filter_map
   - Removed manual binding construction loop
   - Cleaner caller code

3. Made exit_line module public:
   - Allows pattern lowerers to use ExitMetaCollector
   - Clear module visibility boundaries

**Box Design**:
- Single responsibility: Convert ExitMeta + variable_map → exit_bindings
- Pure function: No side effects, testable independently
- Reusable: Can be used by Pattern 3, Pattern 4, etc.

**Testing**:
- Build:  Success (1m 04s)
- Execution:  RC: 0 (Pattern 2 verified)
- Regression:  No issues

**Metrics**:
- New lines: +102 (meta_collector.rs)
- Removed lines: -20 (pattern2_with_break.rs)
- Net change: +82 lines
- Code clarity: Significantly improved

🤖 Generated with Claude Code

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-07 02:37:12 +09:00

205 lines
7.1 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.

//! JoinIR MIR Block Merging Coordinator
//!
//! This module coordinates the merging of JoinIR-generated MIR functions
//! into the host MIR builder. The process is broken into 6 phases:
//!
//! 1. Block ID allocation (block_allocator.rs)
//! 2. Value collection (value_collector.rs)
//! 3. ValueId remapping (uses JoinIrIdRemapper)
//! 4. Instruction rewriting (instruction_rewriter.rs)
//! 5. Exit PHI construction (exit_phi_builder.rs)
//! 6. Boundary reconnection (inline in this file)
//!
//! Phase 4 Refactoring: Breaking down 714-line merge_joinir_mir_blocks() into focused modules
mod block_allocator;
mod value_collector;
mod instruction_rewriter;
mod exit_phi_builder;
pub mod exit_line;
use crate::mir::{MirModule, ValueId};
use crate::mir::join_ir::lowering::inline_boundary::JoinInlineBoundary;
/// Phase 49-3.2: Merge JoinIR-generated MIR blocks into current_function
///
/// # Phase 189: Multi-Function MIR Merge
///
/// This merges JoinIR-generated blocks by:
/// 1. Remapping all block IDs across ALL functions to avoid conflicts
/// 2. Remapping all value IDs across ALL functions to avoid conflicts
/// 3. Adding all blocks from all functions to current_function
/// 4. Jumping from current_block to the entry block
/// 5. Converting Return → Jump to exit block for all functions
///
/// **Multi-Function Support** (Phase 189):
/// - Pattern 1 (Simple While) generates 3 functions: entry + loop_step + k_exit
/// - All functions are flattened into current_function with global ID remapping
/// - Single exit block receives all Return instructions from all functions
///
/// # Phase 188-Impl-3: JoinInlineBoundary Support
///
/// When `boundary` is provided, injects Copy instructions at the entry block
/// to connect host ValueIds to JoinIR local ValueIds:
///
/// ```text
/// entry_block:
/// // Injected by boundary
/// ValueId(100) = Copy ValueId(4) // join_input → host_input
/// // Original JoinIR instructions follow...
/// ```
///
/// This enables clean separation: JoinIR uses local IDs (0,1,2...),
/// host uses its own IDs, and Copy instructions bridge the gap.
///
/// # Returns
///
/// Returns `Ok(Some(exit_phi_id))` if the merged JoinIR functions have return values
/// that were collected into an exit block PHI. さらに、`boundary` に
/// host_outputs が指定されている場合は、exit PHI の結果をホスト側の
/// SSA スロットへ再接続するvariable_map 内の ValueId を更新する)。
pub(in crate::mir::builder) fn merge_joinir_mir_blocks(
builder: &mut crate::mir::builder::MirBuilder,
mir_module: &MirModule,
boundary: Option<&JoinInlineBoundary>,
debug: bool,
) -> Result<Option<ValueId>, String> {
if debug {
eprintln!(
"[cf_loop/joinir] merge_joinir_mir_blocks called with {} functions",
mir_module.functions.len()
);
}
// Phase 1: Allocate block IDs for all functions
let mut remapper = block_allocator::allocate_blocks(builder, mir_module, debug)?;
// Phase 2: Collect values from all functions
let (mut used_values, value_to_func_name, function_params) =
value_collector::collect_values(mir_module, &remapper, debug)?;
// Phase 171-fix: Add condition_bindings' join_values to used_values for remapping
if let Some(boundary) = boundary {
for binding in &boundary.condition_bindings {
if debug {
eprintln!(
"[cf_loop/joinir] Phase 171-fix: Adding condition binding '{}' JoinIR {:?} to used_values",
binding.name, binding.join_value
);
}
used_values.insert(binding.join_value);
}
// Phase 172-3: Add exit_bindings' join_exit_values to used_values for remapping
for binding in &boundary.exit_bindings {
if debug {
eprintln!(
"[cf_loop/joinir] Phase 172-3: Adding exit binding '{}' JoinIR {:?} to used_values",
binding.carrier_name, binding.join_exit_value
);
}
used_values.insert(binding.join_exit_value);
}
}
// Phase 3: Remap ValueIds
remap_values(builder, &used_values, &mut remapper, debug)?;
// Phase 4: Merge blocks and rewrite instructions
let (exit_block_id, exit_phi_inputs) = instruction_rewriter::merge_and_rewrite(
builder,
mir_module,
&mut remapper,
&value_to_func_name,
&function_params,
boundary,
debug,
)?;
// Phase 5: Build exit PHI
let exit_phi_result_id = exit_phi_builder::build_exit_phi(
builder,
exit_block_id,
&exit_phi_inputs,
debug,
)?;
// Phase 6: Reconnect boundary (if specified)
// Phase 197-B: Pass remapper to enable per-carrier exit value lookup
// Phase 33-10-Refactor-P3: Delegate to ExitLineOrchestrator
if let Some(boundary) = boundary {
exit_line::ExitLineOrchestrator::execute(builder, boundary, &remapper, debug)?;
}
// Jump from current block to entry function's entry block
let (entry_func_name, entry_func) = mir_module
.functions
.iter()
.next()
.ok_or("JoinIR module has no functions")?;
let entry_block = remapper
.get_block(entry_func_name, entry_func.entry_block)
.ok_or_else(|| format!("Entry block not found for {}", entry_func_name))?;
if debug {
eprintln!("[cf_loop/joinir] Entry function name: {}", entry_func_name);
eprintln!(
"[cf_loop/joinir] Entry function's entry_block (JoinIR local): {:?}",
entry_func.entry_block
);
eprintln!("[cf_loop/joinir] Entry block (remapped): {:?}", entry_block);
eprintln!(
"[cf_loop/joinir] Current block before emit_jump: {:?}",
builder.current_block
);
eprintln!("[cf_loop/joinir] Jumping to entry block: {:?}", entry_block);
}
crate::mir::builder::emission::branch::emit_jump(builder, entry_block)?;
if debug {
eprintln!(
"[cf_loop/joinir] After emit_jump, current_block: {:?}",
builder.current_block
);
}
// Switch to exit block for subsequent code
builder.start_new_block(exit_block_id)?;
if debug {
eprintln!(
"[cf_loop/joinir] Phase 189: Merge complete: {} functions merged, continuing from {:?}",
mir_module.functions.len(),
exit_block_id
);
}
Ok(exit_phi_result_id)
}
/// Phase 3: Allocate new ValueIds for all collected values
fn remap_values(
builder: &mut crate::mir::builder::MirBuilder,
used_values: &std::collections::BTreeSet<ValueId>,
remapper: &mut crate::mir::builder::joinir_id_remapper::JoinIrIdRemapper,
debug: bool,
) -> Result<(), String> {
if debug {
eprintln!("[cf_loop/joinir] Phase 3: Remapping {} ValueIds", used_values.len());
}
for old_value in used_values {
let new_value = builder.next_value_id();
remapper.set_value(*old_value, new_value);
if debug {
eprintln!(
"[cf_loop/joinir] Value remap: {:?}{:?}",
old_value, new_value
);
}
}
Ok(())
}