From 7e259ad334ea8d1a75922f93949fc338abe4df40 Mon Sep 17 00:00:00 2001 From: tomoaki Date: Thu, 25 Dec 2025 03:28:53 +0900 Subject: [PATCH] refactor(joinir): Phase 286C-2.1 Step 3 - Extract scan logic into scan_blocks() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Move instruction identification logic from main loop to scan_blocks() - Populate RewritePlan with tail_calls, return_conversions - Read-only analysis phase complete (no mutations, just detection) - merge_and_rewrite() now calls scan_blocks() to identify rewrites Scan logic extracted: - Tail call detection: Check Call instructions for intra-module calls - Return detection: Identify Return terminators for exit jump conversion - Populate TailCallRewrite with target_func_name, target_block, args - Populate ReturnConversion with return_value, has_exit_edge_args Build: cargo build --release ✅ 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- .../joinir/merge/instruction_rewriter.rs | 98 ++++++++++++++++++- 1 file changed, 94 insertions(+), 4 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 d55e1945..759f8f6f 100644 --- a/src/mir/builder/control_flow/joinir/merge/instruction_rewriter.rs +++ b/src/mir/builder/control_flow/joinir/merge/instruction_rewriter.rs @@ -107,14 +107,100 @@ fn scan_blocks( ctx: &RewriteContext, debug: bool, ) -> Result { - // TODO: Extract scan logic from merge_and_rewrite - // For now, return empty plan - Ok(RewritePlan { + 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); + }; + } + + let mut plan = RewritePlan { tail_calls: Vec::new(), return_conversions: Vec::new(), phi_adjustments: Vec::new(), parameter_bindings: Vec::new(), - }) + }; + + // Sort functions for deterministic iteration + let mut functions_merge: Vec<_> = mir_module.functions.iter().collect(); + functions_merge.sort_by_key(|(name, _)| name.as_str()); + + for (func_name, func) in functions_merge { + // Sort blocks for deterministic iteration + let mut blocks_merge: Vec<_> = func.blocks.iter().collect(); + blocks_merge.sort_by_key(|(id, _)| id.0); + + for (old_block_id, old_block) in blocks_merge { + let new_block_id = remapper + .get_block(func_name, *old_block_id) + .ok_or_else(|| format!("Block {:?} not found for {}", old_block_id, func_name))?; + + // Scan instructions for tail calls and PHI adjustments + for inst in &old_block.instructions { + // Detect tail calls + if let MirInstruction::Call { func: callee, args, .. } = inst { + if let Some(callee_name) = value_to_func_name.get(callee) { + // Check if this is an intra-module call (tail call candidate) + if let Some(&target_block) = ctx.function_entry_map.get(callee_name) { + let remapped_args: Vec = args + .iter() + .map(|&v| remapper.get_value(v).unwrap_or(v)) + .collect(); + + let is_recursive = callee_name == func_name; + // For now, mark all tail calls as non-continuation (will be refined in plan stage) + let is_continuation = false; + let is_loop_entry = false; // Will be determined in plan stage + + plan.tail_calls.push(TailCallRewrite { + block_id: new_block_id, + target_func_name: callee_name.clone(), + target_block, + args: remapped_args, + is_recursive, + is_continuation, + is_loop_entry, + }); + + log!( + verbose, + "[scan_blocks] Detected tail call: block={:?} target='{}' args={:?}", + new_block_id, callee_name, args + ); + } + } + } + } + + // Check terminator for Return instructions + if let Some(MirInstruction::Return { value }) = &old_block.terminator { + plan.return_conversions.push(ReturnConversion { + block_id: new_block_id, + return_value: *value, + has_exit_edge_args: old_block.edge_args_from_terminator().is_some(), + should_keep_return: false, // Will be determined in plan stage + }); + + log!( + verbose, + "[scan_blocks] Detected return: block={:?} value={:?}", + new_block_id, value + ); + } + } + } + + if debug { + log!( + true, + "[scan_blocks] Plan summary: {} tail calls, {} returns", + plan.tail_calls.len(), + plan.return_conversions.len() + ); + } + + Ok(plan) } /// Stage 2: Plan - Transform plan into concrete rewritten blocks @@ -279,6 +365,10 @@ pub(super) fn merge_and_rewrite( // The issue was that pre-pass used stale remapper values before Phase 33-21 updates. // Instead, we now generate Copies for non-carrier params in the main block processing loop. + // Phase 286C-2.1 Step 2: Call scan_blocks() to establish 3-stage pipeline + // Currently returns empty plan - future steps will extract instruction scanning logic + let _scan_plan = scan_blocks(mir_module, remapper, value_to_func_name, &ctx, debug)?; + // ===== STAGE 2: PLAN (Generate rewritten blocks) ===== // TODO Phase 286C-2.1: Extract to plan_rewrites() // This section should: