From e555b4ad319d4b201abcb33415edefdb91cb371d Mon Sep 17 00:00:00 2001 From: tomoaki Date: Sun, 21 Dec 2025 06:09:45 +0900 Subject: [PATCH] refactor(joinir): Phase 260 P0.1 Step 3 - Extract helpers.rs (is_skippable_continuation) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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) --- .../joinir/merge/instruction_rewriter.rs | 22 +--- .../joinir/merge/rewriter/helpers.rs | 102 ++++++++++++++++++ .../control_flow/joinir/merge/rewriter/mod.rs | 9 +- 3 files changed, 110 insertions(+), 23 deletions(-) create mode 100644 src/mir/builder/control_flow/joinir/merge/rewriter/helpers.rs 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 38d96620..8d52ed44 100644 --- a/src/mir/builder/control_flow/joinir/merge/instruction_rewriter.rs +++ b/src/mir/builder/control_flow/joinir/merge/instruction_rewriter.rs @@ -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, diff --git a/src/mir/builder/control_flow/joinir/merge/rewriter/helpers.rs b/src/mir/builder/control_flow/joinir/merge/rewriter/helpers.rs new file mode 100644 index 00000000..7c8619b0 --- /dev/null +++ b/src/mir/builder/control_flow/joinir/merge/rewriter/helpers.rs @@ -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)); + } +} diff --git a/src/mir/builder/control_flow/joinir/merge/rewriter/mod.rs b/src/mir/builder/control_flow/joinir/merge/rewriter/mod.rs index 848634a9..cb32c9d3 100644 --- a/src/mir/builder/control_flow/joinir/merge/rewriter/mod.rs +++ b/src/mir/builder/control_flow/joinir/merge/rewriter/mod.rs @@ -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)