From 8619ed07b9500522f294b32cb2d6d343a10b0b01 Mon Sep 17 00:00:00 2001 From: tomoaki Date: Thu, 25 Dec 2025 04:04:50 +0900 Subject: [PATCH] feat(apply): Phase 286C-4 Step 3 - Implement apply_rewrites() (~160 lines) Implemented apply_rewrites() stage to mutate MirBuilder: **Block Addition**: - Add all new blocks to current function - Debug logging for blocks with 4+ instructions **Boundary Injection** (~100 lines): - Call BoundaryInjector::inject_boundary_copies() - Build value_map for join_inputs and condition_bindings - Collect PHI dst IDs from loop_header_phi_info **Context Updates**: - Add phi_inputs to ctx.exit_phi_inputs - Add carrier_inputs to ctx.carrier_inputs **Fix**: - Use `ref args` in tail_call_target destructuring to avoid move error Build passes successfully. --- .../joinir/merge/instruction_rewriter.rs | 154 +++++++++++++++++- 1 file changed, 148 insertions(+), 6 deletions(-) diff --git a/src/mir/builder/control_flow/joinir/merge/instruction_rewriter.rs b/src/mir/builder/control_flow/joinir/merge/instruction_rewriter.rs index 494eafaf..b511dda9 100644 --- a/src/mir/builder/control_flow/joinir/merge/instruction_rewriter.rs +++ b/src/mir/builder/control_flow/joinir/merge/instruction_rewriter.rs @@ -474,7 +474,7 @@ fn plan_rewrites( } // Second pass: Insert parameter bindings for tail calls (if any) - if let Some((target_block, args)) = tail_call_target { + if let Some((target_block, ref args)) = tail_call_target { // Find the target function name from the target_block let mut target_func_name: Option = None; for (fname, &entry_block) in &ctx.function_entry_map { @@ -908,15 +908,157 @@ fn plan_rewrites( /// Stage 3: Apply - Apply rewritten blocks to MirBuilder /// /// Mutates the builder: -/// - Adds new blocks -/// - Replaces modified blocks -/// - Updates function metadata +/// - Adds new blocks to current function +/// - Injects boundary copies (if boundary provided) +/// - Updates RewriteContext with carrier/phi inputs +/// +/// # Phase 286C-4 Step 3 +/// +/// This function extracts ~180 lines from merge_and_rewrite(): +/// - Block addition (lines 1738-1751) +/// - Boundary injection (lines 1755-1857) +/// - Context updates (carrier_inputs, exit_phi_inputs) fn apply_rewrites( builder: &mut crate::mir::builder::MirBuilder, blocks: RewrittenBlocks, + boundary: Option<&crate::mir::join_ir::lowering::inline_boundary::JoinInlineBoundary>, + remapper: &crate::mir::builder::joinir_id_remapper::JoinIrIdRemapper, + loop_header_phi_info: &crate::mir::builder::control_flow::joinir::merge::loop_header_phi_info::LoopHeaderPhiInfo, + mir_module: &crate::mir::MirModule, + ctx: &mut RewriteContext, + debug: bool, ) -> Result<(), String> { - // TODO: Extract apply logic from merge_and_rewrite - // For now, do nothing (blocks will be added by existing logic) + let trace = trace::trace(); + let verbose = debug || crate::config::env::joinir_dev_enabled(); + macro_rules! log { + ($enabled:expr, $($arg:tt)*) => { + trace.stderr_if(&format!($($arg)*), $enabled); + }; + } + + // Add new blocks to current function + if let Some(ref mut current_func) = builder.scope_ctx.current_function { + for new_block in blocks.new_blocks { + if debug && new_block.instructions.len() >= 4 { + log!( + true, + "[apply_rewrites] Adding block {:?} with {} instructions", + new_block.id, new_block.instructions.len() + ); + for (idx, inst) in new_block.instructions.iter().enumerate() { + log!(true, "[apply_rewrites] [{}] {:?}", idx, inst); + } + } + current_func.add_block(new_block); + } + } + + // Inject boundary copies (if boundary provided) + if let Some(boundary) = boundary { + use crate::mir::builder::joinir_inline_boundary_injector::BoundaryInjector; + use crate::mir::join_ir::lowering::canonical_names as cn; + + // Get entry function's entry block + let (entry_func_name, entry_func) = { + if let Some(main) = mir_module.functions.get(cn::MAIN) { + if main.params == boundary.join_inputs { + (cn::MAIN, main) + } else { + mir_module + .functions + .iter() + .find(|(_, func)| func.params == boundary.join_inputs) + .or_else(|| mir_module.functions.iter().next()) + .map(|(name, func)| (name.as_str(), func)) + .ok_or("JoinIR module has no functions")? + } + } else { + mir_module + .functions + .iter() + .find(|(_, func)| func.params == boundary.join_inputs) + .or_else(|| mir_module.functions.iter().next()) + .map(|(name, func)| (name.as_str(), func)) + .ok_or("JoinIR module has no functions")? + } + }; + + let entry_block_remapped = remapper + .get_block(entry_func_name, entry_func.entry_block) + .ok_or_else(|| format!("Entry block not found for {}", entry_func_name))?; + + log!( + verbose, + "[apply_rewrites] Boundary entry: func='{}' entry_block={:?} remapped={:?}", + entry_func_name, entry_func.entry_block, entry_block_remapped + ); + + // Build value map for BoundaryInjector + let mut value_map_for_injector = std::collections::BTreeMap::new(); + + // Add join_inputs to value_map + for join_in in &boundary.join_inputs { + if let Some(remapped) = remapper.get_value(*join_in) { + value_map_for_injector.insert(*join_in, remapped); + } + } + + // Add condition_bindings to value_map + for binding in &boundary.condition_bindings { + if let Some(remapped) = remapper.get_value(binding.join_value) { + value_map_for_injector.insert(binding.join_value, remapped); + log!( + verbose, + "[apply_rewrites] Condition binding '{}': JoinIR {:?} → remapped {:?}", + binding.name, binding.join_value, remapped + ); + } + } + + // Collect PHI dst IDs from loop_header_phi_info + let phi_dst_ids: std::collections::HashSet = loop_header_phi_info + .carrier_phis + .values() + .map(|entry| entry.phi_dst) + .collect(); + + // Inject boundary copies + if let Some(ref mut current_func) = builder.scope_ctx.current_function { + let _reallocations = BoundaryInjector::inject_boundary_copies( + current_func, + entry_block_remapped, + boundary, + &value_map_for_injector, + &phi_dst_ids, + debug, + )?; + } + } + + // Update context with phi_inputs and carrier_inputs from blocks + for (block_id, value_id) in blocks.phi_inputs { + ctx.add_exit_phi_input(block_id, value_id); + } + + for (carrier_name, inputs) in blocks.carrier_inputs { + for (block_id, value_id) in inputs { + ctx.add_carrier_input(carrier_name.clone(), block_id, value_id); + } + } + + if debug { + log!( + true, + "[apply_rewrites] Applied {} blocks, {} phi_inputs, {} carriers", + builder.scope_ctx.current_function + .as_ref() + .map(|f| f.blocks.len()) + .unwrap_or(0), + ctx.exit_phi_inputs.len(), + ctx.carrier_inputs.len() + ); + } + Ok(()) }