refactor(joinir): Phase 286C-2.1 Step 3 - Extract scan logic into scan_blocks()
- 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 <noreply@anthropic.com>
This commit is contained in:
@ -107,14 +107,100 @@ fn scan_blocks(
|
||||
ctx: &RewriteContext,
|
||||
debug: bool,
|
||||
) -> Result<RewritePlan, String> {
|
||||
// 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<ValueId> = 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:
|
||||
|
||||
Reference in New Issue
Block a user