refactor(plan): Phase 286C-4 Step 1 - plan_helpers module
Create helper functions to support plan_rewrites() extraction: - build_local_block_map(): Build block ID mapping for a function - sync_spans(): Synchronize instruction spans after rewriting These pure functions will be used by both the current monolithic merge_and_rewrite() and the new plan_rewrites() function. Progress: Step 1/4 (helpers) complete 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@ -47,6 +47,7 @@ pub(super) mod type_propagation; // Phase 260 P0.1 Step 4: Type propagation extr
|
||||
pub(super) mod scan_box; // Stage 1: Read-only scanning for rewrite planning
|
||||
pub(super) mod plan_box; // Stage 2: Pure transformation (scan → blocks)
|
||||
pub(super) mod apply_box; // Stage 3: Builder mutation only
|
||||
pub(super) mod plan_helpers; // Phase 286C-4 Step 1: Helper functions for plan_rewrites()
|
||||
|
||||
// Re-export public API
|
||||
// Phase 260 P0.1 Step 3: From helpers ✅
|
||||
|
||||
@ -0,0 +1,116 @@
|
||||
//! Helper functions for plan_rewrites() stage
|
||||
//!
|
||||
//! Phase 286C-4 Step 1: Extracted from merge_and_rewrite() to support plan_rewrites()
|
||||
//! These are pure helper functions that both the current monolithic code and the
|
||||
//! new plan_rewrites() function can use.
|
||||
|
||||
use crate::mir::{BasicBlock, BasicBlockId, MirFunction, MirInstruction, ValueId};
|
||||
use crate::mir::builder::joinir_id_remapper::JoinIrIdRemapper;
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
/// Build a local block map for a single function
|
||||
///
|
||||
/// Maps old block IDs (from JoinIR function) to new block IDs (in host MIR).
|
||||
/// This is needed for remapping Branch/Jump targets within the same function.
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `func_name` - Name of the function
|
||||
/// * `func` - The function whose blocks to map
|
||||
/// * `remapper` - The ID remapper containing block mappings
|
||||
///
|
||||
/// # Returns
|
||||
/// * BTreeMap<old_block_id, new_block_id> for this function
|
||||
pub fn build_local_block_map(
|
||||
func_name: &str,
|
||||
func: &MirFunction,
|
||||
remapper: &JoinIrIdRemapper,
|
||||
) -> Result<BTreeMap<BasicBlockId, BasicBlockId>, String> {
|
||||
let mut local_block_map = BTreeMap::new();
|
||||
|
||||
for old_block_id in func.blocks.keys() {
|
||||
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))?;
|
||||
local_block_map.insert(*old_block_id, new_block_id);
|
||||
}
|
||||
|
||||
Ok(local_block_map)
|
||||
}
|
||||
|
||||
/// Synchronize instruction spans to match instruction count
|
||||
///
|
||||
/// After adding/removing instructions during rewriting, the instruction_spans
|
||||
/// vector may not match the instructions vector. This function ensures they match.
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `instructions` - The current instructions
|
||||
/// * `old_block` - The original block with spans
|
||||
///
|
||||
/// # Returns
|
||||
/// * A spans vector that matches the instructions length
|
||||
pub fn sync_spans(
|
||||
instructions: &[MirInstruction],
|
||||
old_block: &BasicBlock,
|
||||
) -> Vec<crate::ast::Span> {
|
||||
let inst_count = instructions.len();
|
||||
let mut spans = old_block.instruction_spans.clone();
|
||||
|
||||
if inst_count > spans.len() {
|
||||
// Use a default span for the extra instructions
|
||||
let default_span = spans
|
||||
.last()
|
||||
.copied()
|
||||
.unwrap_or_else(crate::ast::Span::unknown);
|
||||
spans.resize(inst_count, default_span);
|
||||
} else if inst_count < spans.len() {
|
||||
// Truncate spans to match instructions
|
||||
spans.truncate(inst_count);
|
||||
}
|
||||
|
||||
spans
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::ast::Span;
|
||||
|
||||
#[test]
|
||||
fn test_sync_spans_exact_match() {
|
||||
let instructions = vec![
|
||||
MirInstruction::Const { dst: ValueId(1), value: crate::mir::types::ConstValue::Integer(42) },
|
||||
MirInstruction::Const { dst: ValueId(2), value: crate::mir::types::ConstValue::Integer(43) },
|
||||
];
|
||||
let mut block = BasicBlock::new(BasicBlockId(0));
|
||||
block.instruction_spans = vec![Span::unknown(), Span::unknown()];
|
||||
|
||||
let result = sync_spans(&instructions, &block);
|
||||
assert_eq!(result.len(), 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sync_spans_more_instructions() {
|
||||
let instructions = vec![
|
||||
MirInstruction::Const { dst: ValueId(1), value: crate::mir::types::ConstValue::Integer(42) },
|
||||
MirInstruction::Const { dst: ValueId(2), value: crate::mir::types::ConstValue::Integer(43) },
|
||||
MirInstruction::Const { dst: ValueId(3), value: crate::mir::types::ConstValue::Integer(44) },
|
||||
];
|
||||
let mut block = BasicBlock::new(BasicBlockId(0));
|
||||
block.instruction_spans = vec![Span::unknown()];
|
||||
|
||||
let result = sync_spans(&instructions, &block);
|
||||
assert_eq!(result.len(), 3); // Should be padded
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sync_spans_fewer_instructions() {
|
||||
let instructions = vec![
|
||||
MirInstruction::Const { dst: ValueId(1), value: crate::mir::types::ConstValue::Integer(42) },
|
||||
];
|
||||
let mut block = BasicBlock::new(BasicBlockId(0));
|
||||
block.instruction_spans = vec![Span::unknown(), Span::unknown(), Span::unknown()];
|
||||
|
||||
let result = sync_spans(&instructions, &block);
|
||||
assert_eq!(result.len(), 1); // Should be truncated
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user