refactor(joinir): Phase 260 P0.1 Step 3 - Extract helpers.rs (is_skippable_continuation)
Extract is_skippable_continuation to dedicated helpers module. Small pure function (12 lines) with comprehensive tests (3 test cases). Changes: - NEW: rewriter/helpers.rs - is_skippable_continuation + 3 tests - CHANGED: instruction_rewriter.rs - import from helpers (deleted local definition) - CHANGED: rewriter/mod.rs - re-export from helpers Benefits: - Testable in isolation (pure function) - Clear module boundary (structural checks) - instruction_rewriter.rs: 1477 → 1466 lines (-11) Tests: - test_is_skippable_continuation_pure_stub ✅ - test_is_skippable_continuation_has_instructions ✅ - test_is_skippable_continuation_multiple_blocks ✅ Next: Extract type_propagation.rs (propagate_value_type_for_inst - 70 lines)
This commit is contained in:
@ -23,26 +23,8 @@ use crate::mir::{BasicBlock, BasicBlockId, MirFunction, MirInstruction, MirModul
|
||||
use std::collections::BTreeMap; // Phase 222.5-E: HashMap → BTreeMap for determinism
|
||||
use std::collections::BTreeSet;
|
||||
|
||||
/// Phase 132-R0 Task 3: Structural check for skippable continuation functions
|
||||
///
|
||||
/// A continuation function is skippable if it is a pure exit stub:
|
||||
/// - 1 block only
|
||||
/// - No instructions
|
||||
/// - Return terminator only
|
||||
///
|
||||
/// This is a structural check (no by-name/by-id inference).
|
||||
pub(super) fn is_skippable_continuation(func: &MirFunction) -> bool {
|
||||
if func.blocks.len() != 1 {
|
||||
return false;
|
||||
}
|
||||
let Some(block) = func.blocks.get(&func.entry_block) else {
|
||||
return false;
|
||||
};
|
||||
if !block.instructions.is_empty() {
|
||||
return false;
|
||||
}
|
||||
matches!(block.terminator, Some(MirInstruction::Return { .. }))
|
||||
}
|
||||
// Phase 260 P0.1 Step 3: Import from helpers module
|
||||
use super::rewriter::helpers::is_skippable_continuation;
|
||||
|
||||
fn propagate_value_type_for_inst(
|
||||
builder: &mut crate::mir::builder::MirBuilder,
|
||||
|
||||
102
src/mir/builder/control_flow/joinir/merge/rewriter/helpers.rs
Normal file
102
src/mir/builder/control_flow/joinir/merge/rewriter/helpers.rs
Normal file
@ -0,0 +1,102 @@
|
||||
//! Helper utilities for instruction rewriter
|
||||
//!
|
||||
//! Phase 260 P0.1 Step 3: Extracted from instruction_rewriter.rs
|
||||
//! Small, pure functions with no external dependencies.
|
||||
|
||||
use crate::mir::MirFunction;
|
||||
|
||||
/// Phase 132-R0 Task 3: Structural check for skippable continuation functions
|
||||
///
|
||||
/// A continuation function is skippable if it is a pure exit stub:
|
||||
/// - 1 block only
|
||||
/// - No instructions
|
||||
/// - Return terminator only
|
||||
///
|
||||
/// This is a structural check (no by-name/by-id inference).
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```ignore
|
||||
/// // Skippable (pure exit stub)
|
||||
/// fn k_exit(ret_val) {
|
||||
/// return ret_val
|
||||
/// }
|
||||
///
|
||||
/// // Not skippable (has instructions)
|
||||
/// fn k_exit(ret_val) {
|
||||
/// local computed = ret_val + 1
|
||||
/// return computed
|
||||
/// }
|
||||
/// ```
|
||||
pub(in crate::mir::builder::control_flow::joinir::merge) fn is_skippable_continuation(
|
||||
func: &MirFunction,
|
||||
) -> bool {
|
||||
if func.blocks.len() != 1 {
|
||||
return false;
|
||||
}
|
||||
let Some(block) = func.blocks.get(&func.entry_block) else {
|
||||
return false;
|
||||
};
|
||||
if !block.instructions.is_empty() {
|
||||
return false;
|
||||
}
|
||||
matches!(
|
||||
block.terminator,
|
||||
Some(crate::mir::MirInstruction::Return { .. })
|
||||
)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::mir::{BasicBlock, BasicBlockId, MirInstruction};
|
||||
|
||||
#[test]
|
||||
fn test_is_skippable_continuation_pure_stub() {
|
||||
// Pure exit stub: 1 block, no instructions, return only
|
||||
let mut func = MirFunction::new("k_exit".to_string(), vec![]);
|
||||
let entry_block_id = BasicBlockId::new(0);
|
||||
func.entry_block = entry_block_id;
|
||||
|
||||
let mut block = BasicBlock::new(entry_block_id);
|
||||
block.set_terminator(MirInstruction::Return { value: None });
|
||||
func.add_block(block);
|
||||
|
||||
assert!(is_skippable_continuation(&func));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_is_skippable_continuation_has_instructions() {
|
||||
// Has instructions: not skippable
|
||||
let mut func = MirFunction::new("k_exit".to_string(), vec![]);
|
||||
let entry_block_id = BasicBlockId::new(0);
|
||||
func.entry_block = entry_block_id;
|
||||
|
||||
let mut block = BasicBlock::new(entry_block_id);
|
||||
block.instructions.push(MirInstruction::Const {
|
||||
dst: crate::mir::ValueId::new(1),
|
||||
value: crate::mir::types::ConstValue::Integer(42),
|
||||
});
|
||||
block.set_terminator(MirInstruction::Return { value: None });
|
||||
func.add_block(block);
|
||||
|
||||
assert!(!is_skippable_continuation(&func));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_is_skippable_continuation_multiple_blocks() {
|
||||
// Multiple blocks: not skippable
|
||||
let mut func = MirFunction::new("k_exit".to_string(), vec![]);
|
||||
let entry_block_id = BasicBlockId::new(0);
|
||||
func.entry_block = entry_block_id;
|
||||
|
||||
let mut block1 = BasicBlock::new(entry_block_id);
|
||||
block1.set_terminator(MirInstruction::Return { value: None });
|
||||
func.add_block(block1);
|
||||
|
||||
let block2 = BasicBlock::new(BasicBlockId::new(1));
|
||||
func.add_block(block2);
|
||||
|
||||
assert!(!is_skippable_continuation(&func));
|
||||
}
|
||||
}
|
||||
@ -20,16 +20,19 @@
|
||||
//
|
||||
// Modules (extracted):
|
||||
// - logging: DEBUG-177 style verbose logs ✅
|
||||
// - helpers: Small pure functions (is_skippable_continuation) ✅
|
||||
|
||||
// Future modules (pending):
|
||||
// - type_propagation: propagate_value_type_for_inst
|
||||
// - terminator: Branch/Jump/Return remapping
|
||||
// - exit_line: ExitLine/exit-phi wiring
|
||||
// - carriers: loop_invariants, exit_bindings
|
||||
//
|
||||
// For now, re-export from parent to maintain compatibility.
|
||||
|
||||
pub(super) mod helpers; // Phase 260 P0.1 Step 3: Helpers extracted ✅
|
||||
pub(super) mod logging; // Phase 260 P0.1 Step 2: Logging extracted ✅
|
||||
|
||||
// Re-export public API from parent instruction_rewriter module
|
||||
pub(super) use super::instruction_rewriter::is_skippable_continuation;
|
||||
pub(super) use super::instruction_rewriter::merge_and_rewrite;
|
||||
// Re-export public API
|
||||
pub(super) use helpers::is_skippable_continuation; // Phase 260 P0.1 Step 3: From helpers ✅
|
||||
pub(super) use super::instruction_rewriter::merge_and_rewrite; // Still in parent (TODO: extract)
|
||||
|
||||
Reference in New Issue
Block a user