From adccfe5a4e01270c8f2413abc465f34380d6619b Mon Sep 17 00:00:00 2001 From: nyash-codex Date: Sun, 7 Dec 2025 03:26:06 +0900 Subject: [PATCH] refactor(joinir): Phase 33-12 Large module modularization complete MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Task 1: Split mod.rs into if/loop routers - Created if_lowering_router.rs (172 lines): If-expression routing - Created loop_pattern_router.rs (149 lines): Loop pattern routing - Refactored mod.rs (511 → 221 lines): Thin re-export module Task 2: Modularize loop_patterns per-pattern - Created loop_patterns/ directory with 4 pattern files: - simple_while.rs (225 lines): Pattern 1 implementation - with_break.rs (129 lines): Pattern 2 implementation - with_if_phi.rs (123 lines): Pattern 3 implementation - with_continue.rs (129 lines): Pattern 4 stub - Created mod.rs (178 lines): Dispatcher + shared utilities - Removed old loop_patterns.rs (735 lines → directory) Line count changes: - mod.rs: 511 → 221 lines (57% reduction) - loop_patterns: 735 → 784 lines (modularized) - Total: Net +80 lines for better organization Benefits: - Single responsibility per file - Clear pattern boundaries - Improved testability - Better maintainability - Backward compatibility maintained Testing: - cargo build --release: ✅ Success (0 errors) - Regression test: ✅ Pass (RC: 0) --- .../join_ir/lowering/if_lowering_router.rs | 172 ++++ .../join_ir/lowering/loop_pattern_router.rs | 149 ++++ src/mir/join_ir/lowering/loop_patterns.rs | 735 ------------------ src/mir/join_ir/lowering/loop_patterns/mod.rs | 178 +++++ .../lowering/loop_patterns/simple_while.rs | 225 ++++++ .../lowering/loop_patterns/with_break.rs | 129 +++ .../lowering/loop_patterns/with_continue.rs | 129 +++ .../lowering/loop_patterns/with_if_phi.rs | 123 +++ src/mir/join_ir/lowering/mod.rs | 306 +------- 9 files changed, 1113 insertions(+), 1033 deletions(-) create mode 100644 src/mir/join_ir/lowering/if_lowering_router.rs create mode 100644 src/mir/join_ir/lowering/loop_pattern_router.rs delete mode 100644 src/mir/join_ir/lowering/loop_patterns.rs create mode 100644 src/mir/join_ir/lowering/loop_patterns/mod.rs create mode 100644 src/mir/join_ir/lowering/loop_patterns/simple_while.rs create mode 100644 src/mir/join_ir/lowering/loop_patterns/with_break.rs create mode 100644 src/mir/join_ir/lowering/loop_patterns/with_continue.rs create mode 100644 src/mir/join_ir/lowering/loop_patterns/with_if_phi.rs diff --git a/src/mir/join_ir/lowering/if_lowering_router.rs b/src/mir/join_ir/lowering/if_lowering_router.rs new file mode 100644 index 00000000..75591528 --- /dev/null +++ b/src/mir/join_ir/lowering/if_lowering_router.rs @@ -0,0 +1,172 @@ +//! Phase 33-12: If-Expression JoinIR Lowering Router +//! +//! Routes if-expressions to appropriate JoinIR lowering strategies +//! (if_select, if_merge, etc.) +//! +//! # Routing Strategy +//! +//! This router tries multiple lowering strategies in order: +//! 1. **IfMerge**: For multiple-variable patterns (Phase 33-7) +//! 2. **IfSelect**: For single-variable patterns (Phase 33-2/33-3) +//! +//! # Control Flow +//! +//! - Checks toggle flags (`joinir_if_select_enabled()`) +//! - Validates function whitelist (test/Stage-1/explicit approvals) +//! - Excludes loop-lowered functions (Phase 33-9.1 separation) +//! - Falls back to traditional if_phi on pattern mismatch +//! +//! # Phase 61-1: If-in-Loop Support +//! +//! Context parameter enables if-in-loop lowering: +//! - `None`: Pure if-expression +//! - `Some(context)`: If-in-loop with carrier variables + +use crate::mir::join_ir::JoinInst; +use crate::mir::{BasicBlockId, MirFunction}; + +/// Phase 33-7: Try to lower if/else to JoinIR Select/IfMerge instruction +/// +/// Scope: +/// - Only applies to whitelisted functions: +/// - IfSelectTest.* (Phase 33-2/33-3) +/// - IfMergeTest.* (Phase 33-7) +/// - JsonShapeToMap._read_value_from_pair/1 (Phase 33-4 Stage-1) +/// - Stage1JsonScannerBox.value_start_after_key_pos/2 (Phase 33-4 Stage-B) +/// - Requires JoinIR If-select toggle (HAKO_JOINIR_IF_SELECT / joinir_if_select_enabled) +/// - Falls back to traditional if_phi on pattern mismatch +/// +/// Pattern selection: +/// - 1 variable → Select +/// - 2+ variables → IfMerge +/// +/// Phase 61-1: If-in-loop support +/// - `context` parameter: If-in-loop context (carrier_names for loop variables) +/// - None = Pure If, Some(_) = If-in-loop +/// +/// Returns Some(JoinInst::Select) or Some(JoinInst::IfMerge) if pattern matched, None otherwise. +pub fn try_lower_if_to_joinir( + func: &MirFunction, + block_id: BasicBlockId, + debug: bool, + context: Option<&crate::mir::join_ir::lowering::if_phi_context::IfPhiContext>, // Phase 61-1: If-in-loop context +) -> Option { + // 1. dev/Core トグルチェック + // + // - Core: joinir_core_enabled() / joinir_if_select_enabled() + // - Dev: joinir_dev_enabled()(詳細ログ等) + // + // 実際の挙動切り替えは joinir_if_select_enabled() に集約し、 + // Core/Dev ポリシーは config::env 側で判定する。 + if !crate::config::env::joinir_if_select_enabled() { + return None; + } + let core_on = crate::config::env::joinir_core_enabled(); + // Phase 185: strict check moved to caller (if_form.rs) + // let strict_on = crate::config::env::joinir_strict_enabled(); + + // Phase 33-9.1: Loop専任関数の除外(Loop/If責務分離) + // Loop lowering対象関数はIf loweringの対象外にすることで、 + // 1関数につき1 loweringの原則を保証します + if super::is_loop_lowered_function(&func.signature.name) { + return None; + } + + // Phase 33-8: デバッグログレベル取得(0-3) + let debug_level = crate::config::env::joinir_debug_level(); + let _debug = debug || debug_level >= 1; + + // 2. Phase 33-8: 関数名ガード拡張(テスト + Stage-1 rollout + 明示承認) + let is_allowed = + // Test functions (always enabled) + func.signature.name.starts_with("IfSelectTest.") || + func.signature.name.starts_with("IfSelectLocalTest.") || // Phase 33-10 test + func.signature.name.starts_with("IfMergeTest.") || + func.signature.name.starts_with("IfToplevelTest.") || // Phase 61-4: loop-outside if test + func.signature.name.starts_with("Stage1JsonScannerTestBox.") || // Phase 33-5 test + + // Stage-1 rollout (env-controlled) + (crate::config::env::joinir_stage1_enabled() && + func.signature.name.starts_with("Stage1")) || + + // Explicit approvals (Phase 33-4で検証済み, always on) + matches!(func.signature.name.as_str(), + "JsonShapeToMap._read_value_from_pair/1" | + "Stage1JsonScannerBox.value_start_after_key_pos/2" + ); + + // Phase 80: Core ON のときは許可リストを「JoinIRをまず試す」対象とみなす。 + // Core OFF のときは従来どおり whitelist + env に頼る。 + if !is_allowed || !core_on { + // Core OFF かつ許可外なら従来のガードでスキップ + if !is_allowed { + if debug_level >= 2 { + eprintln!( + "[try_lower_if_to_joinir] skipping non-allowed function: {}", + func.signature.name + ); + } + return None; + } + } + // Phase 185: strict_allowed removed (strict check moved to caller: if_form.rs) + + if debug_level >= 1 { + eprintln!( + "[try_lower_if_to_joinir] trying to lower {}", + func.signature.name + ); + } + + // 3. Phase 33-7: IfMerge を優先的に試行(複数変数パターン) + // IfMerge が成功すればそれを返す、失敗したら Select を試行 + // Phase 61-1: context がある場合は with_context() を使用 + let if_merge_lowerer = if let Some(ctx) = context { + crate::mir::join_ir::lowering::if_merge::IfMergeLowerer::with_context(debug_level, ctx.clone()) + } else { + crate::mir::join_ir::lowering::if_merge::IfMergeLowerer::new(debug_level) + }; + + if if_merge_lowerer.can_lower_to_if_merge(func, block_id) { + if let Some(result) = if_merge_lowerer.lower_if_to_if_merge(func, block_id) { + if debug_level >= 1 { + eprintln!( + "[try_lower_if_to_joinir] ✅ IfMerge lowering used for {}", + func.signature.name + ); + } + return Some(result); + } + } + + // 4. IfMerge が失敗したら Select を試行(単一変数パターン) + // Phase 61-1: context がある場合は with_context() を使用 + let if_select_lowerer = if let Some(ctx) = context { + crate::mir::join_ir::lowering::if_select::IfSelectLowerer::with_context(debug_level, ctx.clone()) + } else { + crate::mir::join_ir::lowering::if_select::IfSelectLowerer::new(debug_level) + }; + + // Phase 185: Remove strict checks from lowerer (thin Result-returning box) + // Strict mode panic should happen at caller level (if_form.rs), not here + if !if_select_lowerer.can_lower_to_select(func, block_id) { + if debug_level >= 1 { + eprintln!( + "[try_lower_if_to_joinir] pattern not matched for {}", + func.signature.name + ); + } + return None; + } + + let result = if_select_lowerer.lower_if_to_select(func, block_id); + + if result.is_some() && debug_level >= 1 { + eprintln!( + "[try_lower_if_to_joinir] ✅ Select lowering used for {}", + func.signature.name + ); + } + + result +} diff --git a/src/mir/join_ir/lowering/loop_pattern_router.rs b/src/mir/join_ir/lowering/loop_pattern_router.rs new file mode 100644 index 00000000..6c238cfc --- /dev/null +++ b/src/mir/join_ir/lowering/loop_pattern_router.rs @@ -0,0 +1,149 @@ +//! Phase 33-12: Loop Pattern JoinIR Lowering Router +//! +//! Routes loop patterns to appropriate JoinIR lowering strategies +//! (Pattern 1-4: simple while, break, if+phi, continue) +//! +//! # Routing Strategy +//! +//! This router uses structure-based pattern classification (Phase 194): +//! 1. Extract CFG features from LoopForm +//! 2. Classify into pattern kind (1-4 or Unknown) +//! 3. Route to appropriate pattern lowerer +//! +//! # Pattern Priority (Phase 188) +//! +//! Patterns are tried in complexity order: +//! - **Pattern 4: Continue** (highest complexity) +//! - **Pattern 3: If-Else PHI** (leverages If lowering) +//! - **Pattern 2: Break** (medium complexity) +//! - **Pattern 1: Simple While** (foundational, easiest) +//! +//! # Integration Points +//! +//! Called from: +//! - `loop_to_join.rs::LoopToJoinLowerer::lower_loop()` +//! - `loop_form_intake.rs::handle_loop_form()` + +use crate::mir::join_ir::JoinInst; +use crate::mir::loop_form::LoopForm; + +/// Phase 188: Try to lower loop to JoinIR using pattern-based approach +/// +/// This function routes loop lowering to specific pattern handlers based on +/// loop structure characteristics. It tries patterns in order of complexity: +/// +/// 1. **Pattern 1: Simple While** (foundational, easiest) +/// 2. **Pattern 2: Break** (medium complexity) +/// 3. **Pattern 3: If-Else PHI** (leverages existing If lowering) +/// 4. **Pattern 4: Continue** (highest complexity) +/// +/// # Arguments +/// +/// * `loop_form` - The loop structure to lower +/// * `lowerer` - The LoopToJoinLowerer builder (provides ValueId allocation, etc.) +/// +/// # Returns +/// +/// * `Some(JoinInst)` - Successfully lowered to JoinIR +/// * `None` - No pattern matched (fallback to existing lowering) +/// +/// # Pattern Selection Strategy +/// +/// Patterns are tried sequentially. First matching pattern wins. +/// If no pattern matches, returns `None` to trigger fallback. +/// +/// ## Pattern 1: Simple While Loop +/// - **Condition**: Empty break/continue targets, single latch +/// - **Handler**: `loop_patterns::lower_simple_while_to_joinir()` +/// - **Priority**: First (most common, simplest) +/// +/// ## Pattern 2: Loop with Conditional Break +/// - **Condition**: Non-empty break_targets, exactly 1 break +/// - **Handler**: `loop_patterns::lower_loop_with_break_to_joinir()` +/// - **Priority**: Second (common, medium complexity) +/// +/// ## Pattern 3: Loop with If-Else PHI +/// - **Condition**: Empty break/continue, if-else in body +/// - **Handler**: `loop_patterns::lower_loop_with_conditional_phi_to_joinir()` +/// - **Priority**: Third (reuses If lowering infrastructure) +/// +/// ## Pattern 4: Loop with Continue +/// - **Condition**: Non-empty continue_targets +/// - **Handler**: `loop_patterns::lower_loop_with_continue_to_joinir()` +/// - **Priority**: Fourth (most complex) +/// +/// # Integration Point +/// +/// This function should be called from loop lowering entry points: +/// - `loop_to_join.rs::LoopToJoinLowerer::lower_loop()` +/// - `loop_form_intake.rs::handle_loop_form()` +/// +/// # Example Usage +/// +/// ```rust,ignore +/// use crate::mir::join_ir::lowering::try_lower_loop_pattern_to_joinir; +/// +/// // In loop lowering entry point: +/// if let Some(joinir_inst) = try_lower_loop_pattern_to_joinir(&loop_form, &mut lowerer) { +/// // Pattern matched, use JoinIR +/// return Some(joinir_inst); +/// } +/// // No pattern matched, use existing lowering +/// existing_loop_lowering(&loop_form, &mut lowerer) +/// ``` +/// +/// # Reference +/// +/// See design.md for complete pattern specifications and transformation rules: +/// `docs/private/roadmap2/phases/phase-188-joinir-loop-pattern-expansion/design.md` +pub fn try_lower_loop_pattern_to_joinir( + loop_form: &LoopForm, + lowerer: &mut crate::mir::join_ir::lowering::LoopToJoinLowerer, +) -> Option { + // Phase 194: Structure-based pattern classification + // Tries patterns based on CFG structure, not function names + + use crate::mir::loop_pattern_detection::{classify, extract_features, LoopPatternKind}; + + // Step 1: Extract features from LoopForm (no LoopScope needed for now) + let features = extract_features(loop_form, None); + + // Step 2: Classify pattern based on structure + let pattern = classify(&features); + + // Step 3: Route to appropriate lowerer based on pattern + match pattern { + LoopPatternKind::Pattern4Continue => { + if let Some(inst) = super::loop_patterns::lower_loop_with_continue_to_joinir(loop_form, lowerer) { + eprintln!("[try_lower_loop_pattern] ✅ Pattern 4 (Continue) matched"); + return Some(inst); + } + } + LoopPatternKind::Pattern3IfPhi => { + if let Some(inst) = super::loop_patterns::lower_loop_with_conditional_phi_to_joinir(loop_form, lowerer) { + eprintln!("[try_lower_loop_pattern] ✅ Pattern 3 (If-Else PHI) matched"); + return Some(inst); + } + } + LoopPatternKind::Pattern2Break => { + if let Some(inst) = super::loop_patterns::lower_loop_with_break_to_joinir(loop_form, lowerer) { + eprintln!("[try_lower_loop_pattern] ✅ Pattern 2 (Break) matched"); + return Some(inst); + } + } + LoopPatternKind::Pattern1SimpleWhile => { + if let Some(inst) = super::loop_patterns::lower_simple_while_to_joinir(loop_form, lowerer) { + eprintln!("[try_lower_loop_pattern] ✅ Pattern 1 (Simple While) matched"); + return Some(inst); + } + } + LoopPatternKind::Unknown => { + eprintln!("[try_lower_loop_pattern] ❌ Unknown pattern, fallback to existing lowering"); + } + } + + // No Pattern Matched (fallback to existing lowering) + // =================================================== + eprintln!("[try_lower_loop_pattern] ❌ Pattern lowering failed, fallback to existing lowering"); + None +} diff --git a/src/mir/join_ir/lowering/loop_patterns.rs b/src/mir/join_ir/lowering/loop_patterns.rs deleted file mode 100644 index 49489153..00000000 --- a/src/mir/join_ir/lowering/loop_patterns.rs +++ /dev/null @@ -1,735 +0,0 @@ -//! Loop Pattern Lowering Functions -//! -//! Phase 188 Task 188-4: Skeleton lowering functions for 3 loop patterns. -//! -//! This module provides lowering functions that transform specific loop patterns -//! to JoinIR representation. Each function is a "thin box": -//! - Takes input (LoopForm, builder) -//! - Returns Result (success/error) -//! - No side effects outside the builder -//! -//! ## Patterns -//! -//! 1. **Pattern 1: Simple While Loop** -//! - Foundational pattern (MUST implement first) -//! - Single carrier variable, no breaks/continues -//! - Transforms to: exit check + body + tail recursion -//! -//! 2. **Pattern 2: Loop with Conditional Break** -//! - Builds on Pattern 1 -//! - Adds break handling with multiple exit paths -//! - Transforms to: exit check + break check + body + tail recursion -//! -//! 3. **Pattern 3: Loop with If-Else PHI** -//! - Builds on Pattern 1 -//! - Handles multiple carrier variables with if-else assignment -//! - Reuses existing If lowering (Select/IfMerge) -//! - Transforms to: exit check + if-else (Select) + body + tail recursion -//! -//! ## Reference -//! -//! Design document: `docs/private/roadmap2/phases/phase-188-joinir-loop-pattern-expansion/design.md` -//! -//! Each pattern has complete pseudocode in the design doc that can be adapted -//! to actual Rust implementation. - -use crate::mir::join_ir::lowering::loop_to_join::LoopToJoinLowerer; -use crate::mir::join_ir::JoinInst; -use crate::mir::loop_form::LoopForm; - -// ============================================================================ -// Pattern 1: Simple While Loop -// ============================================================================ - -/// Lowering for Pattern 1: Simple While Loop -/// -/// # Transformation (Pseudocode from design.md) -/// -/// ```text -/// fn loop_step(i): -/// exit_cond = !(i < 3) -/// Jump(k_exit, [], cond=exit_cond) -/// print(i) -/// i_next = i + 1 -/// Call(loop_step, [i_next]) -/// ``` -/// -/// # Steps (from design.md § Pattern 1 § Step-by-Step Transformation) -/// -/// 1. **Extract Loop Variables (Carriers)** -/// - Analyze header PHI nodes -/// - Identify initial values and next values -/// -/// 2. **Create loop_step Function Signature** -/// - Parameters: carrier variables + k_exit continuation -/// -/// 3. **Create k_exit Continuation** -/// - Handles loop exit (returns final value) -/// -/// 4. **Generate Exit Condition Check** -/// - Negate loop condition: `exit_cond = !(i < 3)` -/// - Add Jump to k_exit if exit_cond is true -/// -/// 5. **Translate Loop Body** -/// - Copy body instructions to loop_step body -/// - Preserve side effects (print, etc.) -/// -/// 6. **Generate Tail Recursion** -/// - Update carrier: `i_next = i + 1` -/// - Tail call: `Call(loop_step, [i_next], k_next: None)` -/// -/// 7. **Wire Exit Continuation** -/// - Connect loop_step exit Jump to k_exit -/// - Set k_exit exit_cont to parent continuation -/// -/// # Arguments -/// -/// * `loop_form` - The loop structure to lower -/// * `lowerer` - The LoopToJoinLowerer builder (provides ValueId allocation, etc.) -/// -/// # Returns -/// -/// * `Some(JoinInst)` - Lowering succeeded, returns generated JoinIR instruction -/// * `None` - Lowering failed (pattern not matched or unsupported) -/// -/// # Errors -/// -/// Returns `None` if: -/// - Loop has breaks or continues -/// - Loop has multiple latches -/// - Loop condition is too complex -/// -/// # Reference -/// -/// See design.md § Pattern 1 for complete transformation details and pseudocode. -/// -/// # Example Usage -/// -/// ```rust,ignore -/// use crate::mir::loop_pattern_detection::is_simple_while_pattern; -/// -/// if is_simple_while_pattern(&loop_form) { -/// lower_simple_while_to_joinir(&loop_form, &mut lowerer)?; -/// } -/// ``` -pub fn lower_simple_while_to_joinir( - loop_form: &LoopForm, - lowerer: &mut LoopToJoinLowerer, -) -> Option { - // TODO: Implement Pattern 1 lowering - // - // Step 1: Extract Loop Variables (Carriers) - // ========================================== - // From header PHI: %2 = phi [%1, bb1], [%6, bb4] - // Extract: (var_name: "i", init_value: ValueId(1), next_value: ValueId(6)) - // - // ```rust - // let carriers = extract_carriers_from_header_phi(loop_form)?; - // ``` - // - // Step 2: Create loop_step Function Signature - // ============================================ - // Signature: fn loop_step(i: ValueId, k_exit: JoinContId) -> ... - // - // ```rust - // let loop_step_id = lowerer.allocate_join_func_id(); - // let k_exit_id = lowerer.allocate_join_func_id(); - // - // let mut loop_step_params = vec![]; - // for carrier in &carriers { - // loop_step_params.push(carrier.param_valueid); - // } - // ``` - // - // Step 3: Create k_exit Continuation - // =================================== - // fn k_exit() -> ValueId // Returns final value (0 in this case) - // - // ```rust - // let k_exit_func = JoinFunction { - // id: k_exit_id, - // name: "k_exit".to_string(), - // params: vec![], // No exit values in Pattern 1 - // body: vec![ - // JoinInst::Compute(MirLikeInst::Const { - // dst: lowerer.fresh_valueid(), - // value: ConstValue::Integer(0), - // }), - // JoinInst::Ret { value: Some(return_val) }, - // ], - // exit_cont: None, - // }; - // lowerer.register_join_function(k_exit_func); - // ``` - // - // Step 4: Generate Exit Condition Check - // ====================================== - // exit_cond = !(i < 3) - // Jump(k_exit, [], cond=exit_cond) - // - // ```rust - // let loop_cond = extract_loop_condition_from_header(loop_form)?; - // let exit_cond = lowerer.fresh_valueid(); - // - // body.push(JoinInst::Compute(MirLikeInst::UnaryOp { - // dst: exit_cond, - // op: UnaryOp::Not, - // operand: loop_cond, - // })); - // - // body.push(JoinInst::Jump { - // cont: k_exit_id.as_cont(), - // args: vec![], - // cond: Some(exit_cond), - // }); - // ``` - // - // Step 5: Translate Loop Body - // =========================== - // Copy body instructions to loop_step body - // - // ```rust - // let body_insts = extract_body_instructions(loop_form)?; - // for inst in body_insts { - // body.push(translate_mir_inst_to_joinir(inst, lowerer)?); - // } - // ``` - // - // Step 6: Generate Tail Recursion - // ================================ - // i_next = i + 1 - // Call(loop_step, [i_next], k_next: None) - // - // ```rust - // let const_1 = lowerer.fresh_valueid(); - // let i_next = lowerer.fresh_valueid(); - // - // body.push(JoinInst::Compute(MirLikeInst::Const { - // dst: const_1, - // value: ConstValue::Integer(1), - // })); - // - // body.push(JoinInst::Compute(MirLikeInst::BinOp { - // dst: i_next, - // op: BinOp::Add, - // lhs: i, - // rhs: const_1, - // })); - // - // body.push(JoinInst::Call { - // func: loop_step_id, - // args: vec![i_next], - // k_next: None, // CRITICAL: Must be None (tail call) - // dst: Some(result_var), - // }); - // ``` - // - // Step 7: Wire Exit Continuation - // =============================== - // Connect loop_step to k_exit - // - // ```rust - // let loop_step_func = JoinFunction { - // id: loop_step_id, - // name: "loop_step".to_string(), - // params: loop_step_params, - // body: body, - // exit_cont: Some(k_exit_id.as_cont()), - // }; - // lowerer.register_join_function(loop_step_func); - // ``` - // - // Return success - // ```rust - // Some(JoinInst::Call { ... }) - // ``` - - None -} - -// ============================================================================ -// Pattern 2: Loop with Conditional Break -// ============================================================================ - -/// Lowering for Pattern 2: Loop with Conditional Break -/// -/// # Transformation (Pseudocode from design.md) -/// -/// ```text -/// fn loop_step(i): -/// exit_cond = !(i < 3) -/// Jump(k_exit, [i], cond=exit_cond) // Natural exit -/// break_cond = (i >= 2) -/// Jump(k_exit, [i], cond=break_cond) // Break exit -/// i_next = i + 1 -/// Call(loop_step, [i_next]) -/// ``` -/// -/// # Steps (from design.md § Pattern 2 § Step-by-Step Transformation) -/// -/// 1. **Extract Loop Variables** (same as Pattern 1) -/// 2. **Create loop_step Function** (same as Pattern 1) -/// 3. **Create k_exit with Exit PHI** -/// - k_exit(i_exit) - receives exit value from both exit paths -/// 4. **Generate Natural Exit Check** (same as Pattern 1) -/// 5. **Generate Break Check** -/// - Extract break condition: `break_cond = (i >= 2)` -/// - Add conditional Jump to k_exit: `Jump(k_exit, [i], cond=break_cond)` -/// 6. **Translate Loop Body** (same as Pattern 1) -/// 7. **Generate Tail Recursion** (same as Pattern 1) -/// -/// # Key Difference from Pattern 1 -/// -/// - **Multiple Exit Paths**: Natural exit + break exit -/// - **Exit PHI**: k_exit receives exit value from both paths -/// - **Sequential Jumps**: Natural exit check → break check → body -/// -/// # Arguments -/// -/// * `loop_form` - The loop structure to lower (must have break_targets) -/// * `lowerer` - The LoopToJoinLowerer builder -/// -/// # Returns -/// -/// * `Some(JoinInst)` - Lowering succeeded, returns generated JoinIR instruction -/// * `None` - Lowering failed (pattern not matched or unsupported) -/// -/// # Errors -/// -/// Returns `None` if: -/// - Loop has no breaks (use Pattern 1 instead) -/// - Loop has multiple break targets (not yet supported) -/// - Break is not in an if statement -/// -/// # Reference -/// -/// See design.md § Pattern 2 for complete transformation details and pseudocode. -/// -/// # Example Usage -/// -/// ```rust,ignore -/// use crate::mir::loop_pattern_detection::is_loop_with_break_pattern; -/// -/// if is_loop_with_break_pattern(&loop_form) { -/// lower_loop_with_break_to_joinir(&loop_form, &mut lowerer)?; -/// } -/// ``` -pub fn lower_loop_with_break_to_joinir( - _loop_form: &LoopForm, - _lowerer: &mut LoopToJoinLowerer, -) -> Option { - // Phase 188-Impl-2: Delegate to minimal lowerer - // TODO: Extract LoopScopeShape from loop_form for generic implementation - use crate::mir::join_ir::lowering::loop_scope_shape::LoopScopeShape; - - use crate::mir::BasicBlockId; - use std::collections::{BTreeMap, BTreeSet}; - - // For now, use a placeholder LoopScopeShape - // TODO: Build actual LoopScopeShape from loop_form - let placeholder_scope = LoopScopeShape { - header: BasicBlockId(0), - body: BasicBlockId(0), - latch: BasicBlockId(0), - exit: BasicBlockId(0), - pinned: BTreeSet::new(), - carriers: BTreeSet::new(), - body_locals: BTreeSet::new(), - exit_live: BTreeSet::new(), - progress_carrier: None, - variable_definitions: BTreeMap::new(), - }; - - // Generate JoinIR module - // Phase 169: lower_loop_with_break_minimal now requires condition AST and builder - // This test stub is not used by the actual router, so commenting out for now - // let _join_module = lower_loop_with_break_minimal(placeholder_scope, condition, builder)?; - - // Phase 188-Impl-2: Pattern 2 is now integrated in control_flow.rs via cf_loop_pattern2_with_break() - // This function (lower_loop_with_break_to_joinir) is currently not used by the router. - // The actual lowering happens directly in control_flow.rs which calls loop_with_break_minimal. - // - // TODO: Either: - // 1. Remove this function and rely only on control_flow.rs integration, OR - // 2. Implement JoinModule → JoinInst conversion here (future phase) - - eprintln!("[loop_patterns] Pattern 2: Lowering delegated to control_flow.rs"); - - // Temporary: Return None to trigger fallback - // Pattern 2 currently works via hardcoded route in control_flow.rs - None -} - -// ============================================================================ -// Pattern 3: Loop with If-Else PHI -// ============================================================================ - -/// Lowering for Pattern 3: Loop with If-Else PHI -/// -/// # Transformation (Pseudocode from design.md) -/// -/// ```text -/// fn loop_step(i, sum): -/// exit_cond = !(i <= 5) -/// Jump(k_exit, [sum], cond=exit_cond) -/// sum_new = Select(cond=(i%2==1), then=sum+i, else=sum+0) -/// i_next = i + 1 -/// Call(loop_step, [i_next, sum_new]) -/// ``` -/// -/// # Steps (from design.md § Pattern 3 § Step-by-Step Transformation) -/// -/// 1. **Extract Loop Variables** (multiple carriers: i + sum) -/// 2. **Create loop_step Function** (params: i, sum, k_exit) -/// 3. **Create k_exit with Exit PHI** (receives sum exit value) -/// 4. **Generate Exit Condition Check** (same as Pattern 1) -/// 5. **Translate If-Else to Select** -/// - Use existing If lowering (Phase 33: Select/IfMerge) -/// - Generate: `sum_new = Select(cond, then_val, else_val)` -/// 6. **Translate Loop Body** (remaining instructions) -/// 7. **Generate Tail Recursion** (with multiple carriers: i_next, sum_new) -/// -/// # Key Difference from Pattern 1 -/// -/// - **Multiple Carrier Variables**: Loop updates i + sum -/// - **In-Loop If Lowering**: Reuses existing Select/IfMerge lowering -/// - **PHI in Loop Body**: If-else assigns to same variable (becomes Select) -/// -/// # Arguments -/// -/// * `loop_form` - The loop structure to lower (must have if-else in body) -/// * `lowerer` - The LoopToJoinLowerer builder -/// -/// # Returns -/// -/// * `Some(JoinInst)` - Lowering succeeded, returns generated JoinIR instruction -/// * `None` - Lowering failed (pattern not matched or unsupported) -/// -/// # Errors -/// -/// Returns `None` if: -/// - Loop has breaks or continues -/// - If-else does not assign to same variable -/// - If context cannot be resolved -/// -/// # Reference -/// -/// See design.md § Pattern 3 for complete transformation details and pseudocode. -/// -/// # Example Usage -/// -/// ```rust,ignore -/// use crate::mir::loop_pattern_detection::is_loop_with_conditional_phi_pattern; -/// -/// if is_loop_with_conditional_phi_pattern(&loop_form) { -/// lower_loop_with_conditional_phi_to_joinir(&loop_form, &mut lowerer)?; -/// } -/// ``` -pub fn lower_loop_with_conditional_phi_to_joinir( - _loop_form: &LoopForm, - _lowerer: &mut LoopToJoinLowerer, -) -> Option { - // Phase 188-Impl-3: Delegate to minimal lowerer - // TODO: Extract LoopScopeShape from loop_form for generic implementation - use crate::mir::join_ir::lowering::loop_scope_shape::LoopScopeShape; - use crate::mir::join_ir::lowering::loop_with_if_phi_minimal::lower_loop_with_if_phi_pattern; - use crate::mir::BasicBlockId; - use std::collections::{BTreeMap, BTreeSet}; - - // For now, use a placeholder LoopScopeShape - // TODO: Build actual LoopScopeShape from loop_form - let placeholder_scope = LoopScopeShape { - header: BasicBlockId(0), - body: BasicBlockId(0), - latch: BasicBlockId(0), - exit: BasicBlockId(0), - pinned: BTreeSet::new(), - carriers: BTreeSet::new(), - body_locals: BTreeSet::new(), - exit_live: BTreeSet::new(), - progress_carrier: None, - variable_definitions: BTreeMap::new(), - }; - - // Generate JoinIR module - let _join_module = lower_loop_with_if_phi_pattern(placeholder_scope)?; - - // Phase 188-Impl-3: Pattern 3 is now integrated via the router - // This function delegates to loop_with_if_phi_minimal which generates JoinModule - // - // TODO: Either: - // 1. Remove this function and rely only on router integration, OR - // 2. Implement JoinModule → JoinInst conversion here (future phase) - - eprintln!("[loop_patterns] Pattern 3: Lowering delegated to loop_with_if_phi_minimal"); - - // Temporary: Return None to trigger fallback - // Pattern 3 currently works via router which calls minimal lowerer directly - None -} - -// ============================================================================ -// Pattern 4: Loop with Continue -// ============================================================================ - -/// Lowering for Pattern 4: Loop with Continue -/// -/// # Transformation (Pseudocode) -/// -/// ```text -/// fn loop_step(i, sum): -/// exit_cond = !(i < 10) -/// Jump(k_exit, [sum], cond=exit_cond) // Natural exit -/// i_next = i + 1 -/// continue_cond = (i_next % 2 == 0) -/// Jump(loop_step, [i_next, sum], cond=continue_cond) // Continue jumps to loop start -/// sum_next = sum + i_next -/// Call(loop_step, [i_next, sum_next]) // Normal iteration -/// ``` -/// -/// # Steps (Pattern 4 Transformation) -/// -/// 1. **Extract Loop Variables** (multiple carriers: i + sum) -/// 2. **Create loop_step Function** (params: i, sum, k_exit) -/// 3. **Create k_exit with Exit PHI** (receives sum exit value) -/// 4. **Generate Exit Condition Check** (same as Pattern 1) -/// 5. **Generate Continue Check** -/// - Extract continue condition (if exists) -/// - Add conditional Jump back to loop_step: `Jump(loop_step, [i_next, sum], cond=continue_cond)` -/// 6. **Translate Loop Body** (remaining instructions after continue) -/// 7. **Generate Tail Recursion** (with multiple carriers: i_next, sum_next) -/// -/// # Key Difference from Pattern 1/2/3 -/// -/// - **Continue Jump**: Continue jumps back to loop_step with current carrier values -/// - **Dual Path**: Continue path + normal path (both recursive) -/// - **PHI at Loop Start**: Loop header receives values from both continue and normal paths -/// -/// # Arguments -/// -/// * `loop_form` - The loop structure to lower (must have continue_targets) -/// * `lowerer` - The LoopToJoinLowerer builder -/// -/// # Returns -/// -/// * `Some(JoinInst)` - Lowering succeeded, returns generated JoinIR instruction -/// * `None` - Lowering failed (pattern not matched or unsupported) -/// -/// # Errors -/// -/// Returns `None` if: -/// - Loop has no continues (use Pattern 1 instead) -/// - Loop has break statements (not yet supported) -/// - Continue is not in an if statement -/// -/// # Reference -/// -/// See design.md § Pattern 4 for complete transformation details and pseudocode. -/// -/// # Example Usage -/// -/// ```rust,ignore -/// use crate::mir::loop_pattern_detection::is_loop_with_continue_pattern; -/// -/// if is_loop_with_continue_pattern(&loop_form) { -/// lower_loop_with_continue_to_joinir(&loop_form, &mut lowerer)?; -/// } -/// ``` -pub fn lower_loop_with_continue_to_joinir( - _loop_form: &LoopForm, - _lowerer: &mut LoopToJoinLowerer, -) -> Option { - // Phase 188-Impl-4: Pattern 4 implementation placeholder - // TODO: Implement Pattern 4 lowering - // - // Step 1: Extract Loop Variables (Carriers) - // ========================================== - // From header PHI: %i = phi [%0, preheader], [%i_next, body] - // %sum = phi [%0, preheader], [%sum_next, body] - // Extract: (var_name: "i", init_value: 0, next_value: i_next) - // (var_name: "sum", init_value: 0, next_value: sum_next) - // - // Step 2: Create loop_step Function Signature - // ============================================ - // Signature: fn loop_step(i: ValueId, sum: ValueId, k_exit: JoinContId) -> ... - // - // Step 3: Create k_exit Continuation - // =================================== - // fn k_exit(sum_exit) -> ValueId // Returns final sum value - // - // Step 4: Generate Exit Condition Check - // ====================================== - // exit_cond = !(i < 10) - // Jump(k_exit, [sum], cond=exit_cond) - // - // Step 5: Generate Continue Check - // ================================ - // i_next = i + 1 - // continue_cond = (i_next % 2 == 0) - // Jump(loop_step, [i_next, sum], cond=continue_cond) // Continue to loop start - // - // Step 6: Translate Loop Body (after continue) - // ============================================= - // sum_next = sum + i_next - // - // Step 7: Generate Tail Recursion - // ================================ - // Call(loop_step, [i_next, sum_next], k_next: None) - - eprintln!("[loop_patterns] Pattern 4: Continue lowering not yet implemented"); - None -} - -// ============================================================================ -// Helper Functions (Future Use) -// ============================================================================ - -// TODO: Implement helper functions for extraction and translation -// These will be shared across all 3 patterns (moved from old comments below): -// -// For Pattern 3: -// - extract_carriers_from_header_phi: Extract multiple loop variables (i, sum) -// - extract_if_condition: Find if-else condition in loop body -// - extract_then_value/extract_else_value: Get values from both branches - -// ============================================================================ -// Helper Functions (Future Use) -// ============================================================================ - -// TODO: Implement helper functions for extraction and translation -// These will be shared across all 3 patterns: -// -// 1. extract_carriers_from_header_phi(loop_form) -> Vec -// 2. extract_loop_condition_from_header(loop_form) -> ValueId -// 3. extract_body_instructions(loop_form) -> Vec -// 4. translate_mir_inst_to_joinir(inst, lowerer) -> JoinInst -// 5. find_break_block(loop_form) -> BasicBlockId -// 6. extract_break_condition(block) -> ValueId -// 7. find_if_else_block(loop_form) -> BasicBlockId -// 8. extract_if_condition(block) -> ValueId -// 9. extract_then_value(block) -> ValueId -// 10. extract_else_value(block) -> ValueId - -#[cfg(test)] -mod tests { - use super::*; - - // ======================================================================== - // Pattern 1: Simple While Loop Tests - // ======================================================================== - - #[test] - #[ignore] // TODO: Implement test after lowering logic is complete - fn test_pattern1_lowering_success() { - // TODO: Add integration test for simple while pattern lowering - // Step 1: Create mock LoopForm for simple while pattern - // Step 2: Create mock LoopToJoinLowerer - // Step 3: Call lower_simple_while_to_joinir() - // Step 4: Assert returns Ok(()) - // Step 5: Verify generated JoinIR structure - } - - #[test] - #[ignore] // TODO: Implement test after lowering logic is complete - fn test_pattern1_rejects_break() { - // TODO: Add test that rejects loop with break - // Step 1: Create mock LoopForm with break - // Step 2: Call lower_simple_while_to_joinir() - // Step 3: Assert returns Err(UnsupportedPattern) - } - - // ======================================================================== - // Pattern 2: Loop with Break Tests - // ======================================================================== - - #[test] - #[ignore] // TODO: Implement test after lowering logic is complete - fn test_pattern2_lowering_success() { - // TODO: Add integration test for break pattern lowering - // Step 1: Create mock LoopForm for break pattern - // Step 2: Create mock LoopToJoinLowerer - // Step 3: Call lower_loop_with_break_to_joinir() - // Step 4: Assert returns Ok(()) - // Step 5: Verify generated JoinIR structure (two Jumps to k_exit) - } - - #[test] - #[ignore] // TODO: Implement test after lowering logic is complete - fn test_pattern2_exit_phi_correct() { - // TODO: Add test that verifies k_exit receives correct exit values - // Step 1: Create mock LoopForm for break pattern - // Step 2: Call lower_loop_with_break_to_joinir() - // Step 3: Verify k_exit params = [i_exit] - // Step 4: Verify both Jumps pass current i as argument - } - - // ======================================================================== - // Pattern 3: Loop with If-Else PHI Tests - // ======================================================================== - - #[test] - #[ignore] // TODO: Implement test after lowering logic is complete - fn test_pattern3_lowering_success() { - // TODO: Add integration test for if-else phi pattern lowering - // Step 1: Create mock LoopForm for if-else phi pattern - // Step 2: Create mock LoopToJoinLowerer - // Step 3: Call lower_loop_with_conditional_phi_to_joinir() - // Step 4: Assert returns Ok(()) - // Step 5: Verify generated JoinIR structure (Select instruction) - } - - #[test] - #[ignore] // TODO: Implement test after lowering logic is complete - fn test_pattern3_multiple_carriers() { - // TODO: Add test that verifies multiple carrier variables - // Step 1: Create mock LoopForm with i + sum carriers - // Step 2: Call lower_loop_with_conditional_phi_to_joinir() - // Step 3: Verify loop_step params = [i, sum] - // Step 4: Verify tail Call args = [i_next, sum_new] - } - - #[test] - #[ignore] // TODO: Implement test after lowering logic is complete - fn test_pattern3_if_lowering_integration() { - // TODO: Add test that verifies If lowering integration - // Step 1: Create mock LoopForm with if-else - // Step 2: Call lower_loop_with_conditional_phi_to_joinir() - // Step 3: Verify Select instruction is generated - // Step 4: Verify Select has correct cond/then_val/else_val - } - - // ======================================================================== - // Pattern 4: Loop with Continue Tests - // ======================================================================== - - #[test] - #[ignore] // TODO: Implement test after lowering logic is complete - fn test_pattern4_lowering_success() { - // TODO: Add integration test for continue pattern lowering - // Step 1: Create mock LoopForm for continue pattern - // Step 2: Create mock LoopToJoinLowerer - // Step 3: Call lower_loop_with_continue_to_joinir() - // Step 4: Assert returns Ok(()) - // Step 5: Verify generated JoinIR structure (Jump to loop_step on continue) - } - - #[test] - #[ignore] // TODO: Implement test after lowering logic is complete - fn test_pattern4_continue_jump_correct() { - // TODO: Add test that verifies continue jumps to loop_step - // Step 1: Create mock LoopForm for continue pattern - // Step 2: Call lower_loop_with_continue_to_joinir() - // Step 3: Verify conditional Jump targets loop_step - // Step 4: Verify Jump passes current carrier values as arguments - } - - #[test] - #[ignore] // TODO: Implement test after lowering logic is complete - fn test_pattern4_multiple_carriers() { - // TODO: Add test that verifies multiple carrier variables - // Step 1: Create mock LoopForm with i + sum carriers - // Step 2: Call lower_loop_with_continue_to_joinir() - // Step 3: Verify loop_step params = [i, sum] - // Step 4: Verify both tail Call and continue Jump use [i_next, sum_next] - } -} diff --git a/src/mir/join_ir/lowering/loop_patterns/mod.rs b/src/mir/join_ir/lowering/loop_patterns/mod.rs new file mode 100644 index 00000000..510a216f --- /dev/null +++ b/src/mir/join_ir/lowering/loop_patterns/mod.rs @@ -0,0 +1,178 @@ +//! Phase 33-12: Loop Pattern Lowering Module +//! +//! Implements JoinIR lowering for different loop patterns: +//! - Pattern 1: Simple while loops (no break/continue) +//! - Pattern 2: Loops with break statements +//! - Pattern 3: Loops with if expressions + PHI merging +//! - Pattern 4: Loops with continue statements (stub) +//! +//! # Module Structure +//! +//! Each pattern is implemented in its own file: +//! - `simple_while.rs`: Pattern 1 implementation +//! - `with_break.rs`: Pattern 2 implementation +//! - `with_if_phi.rs`: Pattern 3 implementation +//! - `with_continue.rs`: Pattern 4 stub +//! +//! # Design Philosophy +//! +//! Pattern lowering functions are "thin boxes": +//! - Takes input (LoopForm, builder) +//! - Returns Result (success/error) +//! - No side effects outside the builder +//! +//! # Reference +//! +//! Design document: `docs/private/roadmap2/phases/phase-188-joinir-loop-pattern-expansion/design.md` + +pub mod simple_while; +pub mod with_break; +pub mod with_if_phi; +pub mod with_continue; + +pub use simple_while::lower_simple_while_to_joinir; +pub use with_break::lower_loop_with_break_to_joinir; +pub use with_if_phi::lower_loop_with_conditional_phi_to_joinir; +pub use with_continue::lower_loop_with_continue_to_joinir; + +// ============================================================================ +// Helper Functions (Shared Utilities) +// ============================================================================ + +// TODO: Implement helper functions for extraction and translation +// These will be shared across all 4 patterns: +// +// 1. extract_carriers_from_header_phi(loop_form) -> Vec +// 2. extract_loop_condition_from_header(loop_form) -> ValueId +// 3. extract_body_instructions(loop_form) -> Vec +// 4. translate_mir_inst_to_joinir(inst, lowerer) -> JoinInst +// 5. find_break_block(loop_form) -> BasicBlockId +// 6. extract_break_condition(block) -> ValueId +// 7. find_if_else_block(loop_form) -> BasicBlockId +// 8. extract_if_condition(block) -> ValueId +// 9. extract_then_value(block) -> ValueId +// 10. extract_else_value(block) -> ValueId + +#[cfg(test)] +mod tests { + use super::*; + + // ======================================================================== + // Pattern 1: Simple While Loop Tests + // ======================================================================== + + #[test] + #[ignore] // TODO: Implement test after lowering logic is complete + fn test_pattern1_lowering_success() { + // TODO: Add integration test for simple while pattern lowering + // Step 1: Create mock LoopForm for simple while pattern + // Step 2: Create mock LoopToJoinLowerer + // Step 3: Call lower_simple_while_to_joinir() + // Step 4: Assert returns Some(JoinInst) + // Step 5: Verify generated JoinIR structure + } + + #[test] + #[ignore] // TODO: Implement test after lowering logic is complete + fn test_pattern1_rejects_break() { + // TODO: Add test that rejects loop with break + // Step 1: Create mock LoopForm with break + // Step 2: Call lower_simple_while_to_joinir() + // Step 3: Assert returns None (unsupported pattern) + } + + // ======================================================================== + // Pattern 2: Loop with Break Tests + // ======================================================================== + + #[test] + #[ignore] // TODO: Implement test after lowering logic is complete + fn test_pattern2_lowering_success() { + // TODO: Add integration test for break pattern lowering + // Step 1: Create mock LoopForm for break pattern + // Step 2: Create mock LoopToJoinLowerer + // Step 3: Call lower_loop_with_break_to_joinir() + // Step 4: Assert returns Some(JoinInst) + // Step 5: Verify generated JoinIR structure (two Jumps to k_exit) + } + + #[test] + #[ignore] // TODO: Implement test after lowering logic is complete + fn test_pattern2_exit_phi_correct() { + // TODO: Add test that verifies k_exit receives correct exit values + // Step 1: Create mock LoopForm for break pattern + // Step 2: Call lower_loop_with_break_to_joinir() + // Step 3: Verify k_exit params = [i_exit] + // Step 4: Verify both Jumps pass current i as argument + } + + // ======================================================================== + // Pattern 3: Loop with If-Else PHI Tests + // ======================================================================== + + #[test] + #[ignore] // TODO: Implement test after lowering logic is complete + fn test_pattern3_lowering_success() { + // TODO: Add integration test for if-else phi pattern lowering + // Step 1: Create mock LoopForm for if-else phi pattern + // Step 2: Create mock LoopToJoinLowerer + // Step 3: Call lower_loop_with_conditional_phi_to_joinir() + // Step 4: Assert returns Some(JoinInst) + // Step 5: Verify generated JoinIR structure (Select instruction) + } + + #[test] + #[ignore] // TODO: Implement test after lowering logic is complete + fn test_pattern3_multiple_carriers() { + // TODO: Add test that verifies multiple carrier variables + // Step 1: Create mock LoopForm with i + sum carriers + // Step 2: Call lower_loop_with_conditional_phi_to_joinir() + // Step 3: Verify loop_step params = [i, sum] + // Step 4: Verify tail Call args = [i_next, sum_new] + } + + #[test] + #[ignore] // TODO: Implement test after lowering logic is complete + fn test_pattern3_if_lowering_integration() { + // TODO: Add test that verifies If lowering integration + // Step 1: Create mock LoopForm with if-else + // Step 2: Call lower_loop_with_conditional_phi_to_joinir() + // Step 3: Verify Select instruction is generated + // Step 4: Verify Select has correct cond/then_val/else_val + } + + // ======================================================================== + // Pattern 4: Loop with Continue Tests + // ======================================================================== + + #[test] + #[ignore] // TODO: Implement test after lowering logic is complete + fn test_pattern4_lowering_success() { + // TODO: Add integration test for continue pattern lowering + // Step 1: Create mock LoopForm for continue pattern + // Step 2: Create mock LoopToJoinLowerer + // Step 3: Call lower_loop_with_continue_to_joinir() + // Step 4: Assert returns Some(JoinInst) + // Step 5: Verify generated JoinIR structure (Jump to loop_step on continue) + } + + #[test] + #[ignore] // TODO: Implement test after lowering logic is complete + fn test_pattern4_continue_jump_correct() { + // TODO: Add test that verifies continue jumps to loop_step + // Step 1: Create mock LoopForm for continue pattern + // Step 2: Call lower_loop_with_continue_to_joinir() + // Step 3: Verify conditional Jump targets loop_step + // Step 4: Verify Jump passes current carrier values as arguments + } + + #[test] + #[ignore] // TODO: Implement test after lowering logic is complete + fn test_pattern4_multiple_carriers() { + // TODO: Add test that verifies multiple carrier variables + // Step 1: Create mock LoopForm with i + sum carriers + // Step 2: Call lower_loop_with_continue_to_joinir() + // Step 3: Verify loop_step params = [i, sum] + // Step 4: Verify both tail Call and continue Jump use [i_next, sum_next] + } +} diff --git a/src/mir/join_ir/lowering/loop_patterns/simple_while.rs b/src/mir/join_ir/lowering/loop_patterns/simple_while.rs new file mode 100644 index 00000000..f64494e5 --- /dev/null +++ b/src/mir/join_ir/lowering/loop_patterns/simple_while.rs @@ -0,0 +1,225 @@ +//! Pattern 1: Simple While Loop Lowering +//! +//! Target: Simple while loops with no break/continue +//! Example: `while(i < 10) { i = i + 1 }` +//! +//! # Transformation +//! +//! ```text +//! fn loop_step(i): +//! exit_cond = !(i < 3) +//! Jump(k_exit, [], cond=exit_cond) +//! print(i) +//! i_next = i + 1 +//! Call(loop_step, [i_next]) +//! ``` + +use crate::mir::join_ir::lowering::loop_to_join::LoopToJoinLowerer; +use crate::mir::join_ir::JoinInst; +use crate::mir::loop_form::LoopForm; + +/// Lowering for Pattern 1: Simple While Loop +/// +/// # Transformation (Pseudocode from design.md) +/// +/// ```text +/// fn loop_step(i): +/// exit_cond = !(i < 3) +/// Jump(k_exit, [], cond=exit_cond) +/// print(i) +/// i_next = i + 1 +/// Call(loop_step, [i_next]) +/// ``` +/// +/// # Steps (from design.md § Pattern 1 § Step-by-Step Transformation) +/// +/// 1. **Extract Loop Variables (Carriers)** +/// - Analyze header PHI nodes +/// - Identify initial values and next values +/// +/// 2. **Create loop_step Function Signature** +/// - Parameters: carrier variables + k_exit continuation +/// +/// 3. **Create k_exit Continuation** +/// - Handles loop exit (returns final value) +/// +/// 4. **Generate Exit Condition Check** +/// - Negate loop condition: `exit_cond = !(i < 3)` +/// - Add Jump to k_exit if exit_cond is true +/// +/// 5. **Translate Loop Body** +/// - Copy body instructions to loop_step body +/// - Preserve side effects (print, etc.) +/// +/// 6. **Generate Tail Recursion** +/// - Update carrier: `i_next = i + 1` +/// - Tail call: `Call(loop_step, [i_next], k_next: None)` +/// +/// 7. **Wire Exit Continuation** +/// - Connect loop_step exit Jump to k_exit +/// - Set k_exit exit_cont to parent continuation +/// +/// # Arguments +/// +/// * `loop_form` - The loop structure to lower +/// * `lowerer` - The LoopToJoinLowerer builder (provides ValueId allocation, etc.) +/// +/// # Returns +/// +/// * `Some(JoinInst)` - Lowering succeeded, returns generated JoinIR instruction +/// * `None` - Lowering failed (pattern not matched or unsupported) +/// +/// # Errors +/// +/// Returns `None` if: +/// - Loop has breaks or continues +/// - Loop has multiple latches +/// - Loop condition is too complex +/// +/// # Reference +/// +/// See design.md § Pattern 1 for complete transformation details and pseudocode. +/// +/// # Example Usage +/// +/// ```rust,ignore +/// use crate::mir::loop_pattern_detection::is_simple_while_pattern; +/// +/// if is_simple_while_pattern(&loop_form) { +/// lower_simple_while_to_joinir(&loop_form, &mut lowerer)?; +/// } +/// ``` +pub fn lower_simple_while_to_joinir( + loop_form: &LoopForm, + lowerer: &mut LoopToJoinLowerer, +) -> Option { + // TODO: Implement Pattern 1 lowering + // + // Step 1: Extract Loop Variables (Carriers) + // ========================================== + // From header PHI: %2 = phi [%1, bb1], [%6, bb4] + // Extract: (var_name: "i", init_value: ValueId(1), next_value: ValueId(6)) + // + // ```rust + // let carriers = extract_carriers_from_header_phi(loop_form)?; + // ``` + // + // Step 2: Create loop_step Function Signature + // ============================================ + // Signature: fn loop_step(i: ValueId, k_exit: JoinContId) -> ... + // + // ```rust + // let loop_step_id = lowerer.allocate_join_func_id(); + // let k_exit_id = lowerer.allocate_join_func_id(); + // + // let mut loop_step_params = vec![]; + // for carrier in &carriers { + // loop_step_params.push(carrier.param_valueid); + // } + // ``` + // + // Step 3: Create k_exit Continuation + // =================================== + // fn k_exit() -> ValueId // Returns final value (0 in this case) + // + // ```rust + // let k_exit_func = JoinFunction { + // id: k_exit_id, + // name: "k_exit".to_string(), + // params: vec![], // No exit values in Pattern 1 + // body: vec![ + // JoinInst::Compute(MirLikeInst::Const { + // dst: lowerer.fresh_valueid(), + // value: ConstValue::Integer(0), + // }), + // JoinInst::Ret { value: Some(return_val) }, + // ], + // exit_cont: None, + // }; + // lowerer.register_join_function(k_exit_func); + // ``` + // + // Step 4: Generate Exit Condition Check + // ====================================== + // exit_cond = !(i < 3) + // Jump(k_exit, [], cond=exit_cond) + // + // ```rust + // let loop_cond = extract_loop_condition_from_header(loop_form)?; + // let exit_cond = lowerer.fresh_valueid(); + // + // body.push(JoinInst::Compute(MirLikeInst::UnaryOp { + // dst: exit_cond, + // op: UnaryOp::Not, + // operand: loop_cond, + // })); + // + // body.push(JoinInst::Jump { + // cont: k_exit_id.as_cont(), + // args: vec![], + // cond: Some(exit_cond), + // }); + // ``` + // + // Step 5: Translate Loop Body + // =========================== + // Copy body instructions to loop_step body + // + // ```rust + // let body_insts = extract_body_instructions(loop_form)?; + // for inst in body_insts { + // body.push(translate_mir_inst_to_joinir(inst, lowerer)?); + // } + // ``` + // + // Step 6: Generate Tail Recursion + // ================================ + // i_next = i + 1 + // Call(loop_step, [i_next], k_next: None) + // + // ```rust + // let const_1 = lowerer.fresh_valueid(); + // let i_next = lowerer.fresh_valueid(); + // + // body.push(JoinInst::Compute(MirLikeInst::Const { + // dst: const_1, + // value: ConstValue::Integer(1), + // })); + // + // body.push(JoinInst::Compute(MirLikeInst::BinOp { + // dst: i_next, + // op: BinOp::Add, + // lhs: i, + // rhs: const_1, + // })); + // + // body.push(JoinInst::Call { + // func: loop_step_id, + // args: vec![i_next], + // k_next: None, // CRITICAL: Must be None (tail call) + // dst: Some(result_var), + // }); + // ``` + // + // Step 7: Wire Exit Continuation + // =============================== + // Connect loop_step to k_exit + // + // ```rust + // let loop_step_func = JoinFunction { + // id: loop_step_id, + // name: "loop_step".to_string(), + // params: loop_step_params, + // body: body, + // exit_cont: Some(k_exit_id.as_cont()), + // }; + // lowerer.register_join_function(loop_step_func); + // ``` + // + // Return success + // ```rust + // Some(JoinInst::Call { ... }) + // ``` + + None +} diff --git a/src/mir/join_ir/lowering/loop_patterns/with_break.rs b/src/mir/join_ir/lowering/loop_patterns/with_break.rs new file mode 100644 index 00000000..9d5d62e0 --- /dev/null +++ b/src/mir/join_ir/lowering/loop_patterns/with_break.rs @@ -0,0 +1,129 @@ +//! Pattern 2: Loop with Break Lowering +//! +//! Target: Loops with conditional break statements +//! Example: `while(i < 10) { if i >= 5 { break } i = i + 1 }` +//! +//! # Transformation +//! +//! ```text +//! fn loop_step(i): +//! exit_cond = !(i < 3) +//! Jump(k_exit, [i], cond=exit_cond) // Natural exit +//! break_cond = (i >= 2) +//! Jump(k_exit, [i], cond=break_cond) // Break exit +//! i_next = i + 1 +//! Call(loop_step, [i_next]) +//! ``` + +use crate::mir::join_ir::lowering::loop_to_join::LoopToJoinLowerer; +use crate::mir::join_ir::JoinInst; +use crate::mir::loop_form::LoopForm; + +/// Lowering for Pattern 2: Loop with Conditional Break +/// +/// # Transformation (Pseudocode from design.md) +/// +/// ```text +/// fn loop_step(i): +/// exit_cond = !(i < 3) +/// Jump(k_exit, [i], cond=exit_cond) // Natural exit +/// break_cond = (i >= 2) +/// Jump(k_exit, [i], cond=break_cond) // Break exit +/// i_next = i + 1 +/// Call(loop_step, [i_next]) +/// ``` +/// +/// # Steps (from design.md § Pattern 2 § Step-by-Step Transformation) +/// +/// 1. **Extract Loop Variables** (same as Pattern 1) +/// 2. **Create loop_step Function** (same as Pattern 1) +/// 3. **Create k_exit with Exit PHI** +/// - k_exit(i_exit) - receives exit value from both exit paths +/// 4. **Generate Natural Exit Check** (same as Pattern 1) +/// 5. **Generate Break Check** +/// - Extract break condition: `break_cond = (i >= 2)` +/// - Add conditional Jump to k_exit: `Jump(k_exit, [i], cond=break_cond)` +/// 6. **Translate Loop Body** (same as Pattern 1) +/// 7. **Generate Tail Recursion** (same as Pattern 1) +/// +/// # Key Difference from Pattern 1 +/// +/// - **Multiple Exit Paths**: Natural exit + break exit +/// - **Exit PHI**: k_exit receives exit value from both paths +/// - **Sequential Jumps**: Natural exit check → break check → body +/// +/// # Arguments +/// +/// * `loop_form` - The loop structure to lower (must have break_targets) +/// * `lowerer` - The LoopToJoinLowerer builder +/// +/// # Returns +/// +/// * `Some(JoinInst)` - Lowering succeeded, returns generated JoinIR instruction +/// * `None` - Lowering failed (pattern not matched or unsupported) +/// +/// # Errors +/// +/// Returns `None` if: +/// - Loop has no breaks (use Pattern 1 instead) +/// - Loop has multiple break targets (not yet supported) +/// - Break is not in an if statement +/// +/// # Reference +/// +/// See design.md § Pattern 2 for complete transformation details and pseudocode. +/// +/// # Example Usage +/// +/// ```rust,ignore +/// use crate::mir::loop_pattern_detection::is_loop_with_break_pattern; +/// +/// if is_loop_with_break_pattern(&loop_form) { +/// lower_loop_with_break_to_joinir(&loop_form, &mut lowerer)?; +/// } +/// ``` +pub fn lower_loop_with_break_to_joinir( + _loop_form: &LoopForm, + _lowerer: &mut LoopToJoinLowerer, +) -> Option { + // Phase 188-Impl-2: Delegate to minimal lowerer + // TODO: Extract LoopScopeShape from loop_form for generic implementation + use crate::mir::join_ir::lowering::loop_scope_shape::LoopScopeShape; + + use crate::mir::BasicBlockId; + use std::collections::{BTreeMap, BTreeSet}; + + // For now, use a placeholder LoopScopeShape + // TODO: Build actual LoopScopeShape from loop_form + let _placeholder_scope = LoopScopeShape { + header: BasicBlockId(0), + body: BasicBlockId(0), + latch: BasicBlockId(0), + exit: BasicBlockId(0), + pinned: BTreeSet::new(), + carriers: BTreeSet::new(), + body_locals: BTreeSet::new(), + exit_live: BTreeSet::new(), + progress_carrier: None, + variable_definitions: BTreeMap::new(), + }; + + // Generate JoinIR module + // Phase 169: lower_loop_with_break_minimal now requires condition AST and builder + // This test stub is not used by the actual router, so commenting out for now + // let _join_module = lower_loop_with_break_minimal(placeholder_scope, condition, builder)?; + + // Phase 188-Impl-2: Pattern 2 is now integrated in control_flow.rs via cf_loop_pattern2_with_break() + // This function (lower_loop_with_break_to_joinir) is currently not used by the router. + // The actual lowering happens directly in control_flow.rs which calls loop_with_break_minimal. + // + // TODO: Either: + // 1. Remove this function and rely only on control_flow.rs integration, OR + // 2. Implement JoinModule → JoinInst conversion here (future phase) + + eprintln!("[loop_patterns] Pattern 2: Lowering delegated to control_flow.rs"); + + // Temporary: Return None to trigger fallback + // Pattern 2 currently works via hardcoded route in control_flow.rs + None +} diff --git a/src/mir/join_ir/lowering/loop_patterns/with_continue.rs b/src/mir/join_ir/lowering/loop_patterns/with_continue.rs new file mode 100644 index 00000000..5c8cd0fc --- /dev/null +++ b/src/mir/join_ir/lowering/loop_patterns/with_continue.rs @@ -0,0 +1,129 @@ +//! Pattern 4: Loop with Continue - STUB +//! +//! Target: Loops with continue statements +//! Status: Deferred to Phase 195+ +//! +//! # Transformation +//! +//! ```text +//! fn loop_step(i, sum): +//! exit_cond = !(i < 10) +//! Jump(k_exit, [sum], cond=exit_cond) // Natural exit +//! i_next = i + 1 +//! continue_cond = (i_next % 2 == 0) +//! Jump(loop_step, [i_next, sum], cond=continue_cond) // Continue jumps to loop start +//! sum_next = sum + i_next +//! Call(loop_step, [i_next, sum_next]) // Normal iteration +//! ``` + +use crate::mir::join_ir::lowering::loop_to_join::LoopToJoinLowerer; +use crate::mir::join_ir::JoinInst; +use crate::mir::loop_form::LoopForm; + +/// Lowering for Pattern 4: Loop with Continue +/// +/// # Transformation (Pseudocode) +/// +/// ```text +/// fn loop_step(i, sum): +/// exit_cond = !(i < 10) +/// Jump(k_exit, [sum], cond=exit_cond) // Natural exit +/// i_next = i + 1 +/// continue_cond = (i_next % 2 == 0) +/// Jump(loop_step, [i_next, sum], cond=continue_cond) // Continue jumps to loop start +/// sum_next = sum + i_next +/// Call(loop_step, [i_next, sum_next]) // Normal iteration +/// ``` +/// +/// # Steps (Pattern 4 Transformation) +/// +/// 1. **Extract Loop Variables** (multiple carriers: i + sum) +/// 2. **Create loop_step Function** (params: i, sum, k_exit) +/// 3. **Create k_exit with Exit PHI** (receives sum exit value) +/// 4. **Generate Exit Condition Check** (same as Pattern 1) +/// 5. **Generate Continue Check** +/// - Extract continue condition (if exists) +/// - Add conditional Jump back to loop_step: `Jump(loop_step, [i_next, sum], cond=continue_cond)` +/// 6. **Translate Loop Body** (remaining instructions after continue) +/// 7. **Generate Tail Recursion** (with multiple carriers: i_next, sum_next) +/// +/// # Key Difference from Pattern 1/2/3 +/// +/// - **Continue Jump**: Continue jumps back to loop_step with current carrier values +/// - **Dual Path**: Continue path + normal path (both recursive) +/// - **PHI at Loop Start**: Loop header receives values from both continue and normal paths +/// +/// # Arguments +/// +/// * `loop_form` - The loop structure to lower (must have continue_targets) +/// * `lowerer` - The LoopToJoinLowerer builder +/// +/// # Returns +/// +/// * `Some(JoinInst)` - Lowering succeeded, returns generated JoinIR instruction +/// * `None` - Lowering failed (pattern not matched or unsupported) +/// +/// # Errors +/// +/// Returns `None` if: +/// - Loop has no continues (use Pattern 1 instead) +/// - Loop has break statements (not yet supported) +/// - Continue is not in an if statement +/// +/// # Reference +/// +/// See design.md § Pattern 4 for complete transformation details and pseudocode. +/// +/// # Example Usage +/// +/// ```rust,ignore +/// use crate::mir::loop_pattern_detection::is_loop_with_continue_pattern; +/// +/// if is_loop_with_continue_pattern(&loop_form) { +/// lower_loop_with_continue_to_joinir(&loop_form, &mut lowerer)?; +/// } +/// ``` +pub fn lower_loop_with_continue_to_joinir( + _loop_form: &LoopForm, + _lowerer: &mut LoopToJoinLowerer, +) -> Option { + // Phase 188-Impl-4: Pattern 4 implementation placeholder + // TODO: Implement Pattern 4 lowering + // + // Step 1: Extract Loop Variables (Carriers) + // ========================================== + // From header PHI: %i = phi [%0, preheader], [%i_next, body] + // %sum = phi [%0, preheader], [%sum_next, body] + // Extract: (var_name: "i", init_value: 0, next_value: i_next) + // (var_name: "sum", init_value: 0, next_value: sum_next) + // + // Step 2: Create loop_step Function Signature + // ============================================ + // Signature: fn loop_step(i: ValueId, sum: ValueId, k_exit: JoinContId) -> ... + // + // Step 3: Create k_exit Continuation + // =================================== + // fn k_exit(sum_exit) -> ValueId // Returns final sum value + // + // Step 4: Generate Exit Condition Check + // ====================================== + // exit_cond = !(i < 10) + // Jump(k_exit, [sum], cond=exit_cond) + // + // Step 5: Generate Continue Check + // ================================ + // i_next = i + 1 + // continue_cond = (i_next % 2 == 0) + // Jump(loop_step, [i_next, sum], cond=continue_cond) // Continue to loop start + // + // Step 6: Translate Loop Body (after continue) + // ============================================= + // sum_next = sum + i_next + // + // Step 7: Generate Tail Recursion + // ================================ + // Call(loop_step, [i_next, sum_next], k_next: None) + + eprintln!("[loop_patterns] Pattern 4: Continue lowering not yet implemented"); + None +} diff --git a/src/mir/join_ir/lowering/loop_patterns/with_if_phi.rs b/src/mir/join_ir/lowering/loop_patterns/with_if_phi.rs new file mode 100644 index 00000000..91fa0a12 --- /dev/null +++ b/src/mir/join_ir/lowering/loop_patterns/with_if_phi.rs @@ -0,0 +1,123 @@ +//! Pattern 3: Loop with If-Else PHI Lowering +//! +//! Target: Loops with if expressions inside that merge values +//! Example: `while(i < 10) { if x { y = 1 } else { y = 2 } }` +//! +//! # Transformation +//! +//! ```text +//! fn loop_step(i, sum): +//! exit_cond = !(i <= 5) +//! Jump(k_exit, [sum], cond=exit_cond) +//! sum_new = Select(cond=(i%2==1), then=sum+i, else=sum+0) +//! i_next = i + 1 +//! Call(loop_step, [i_next, sum_new]) +//! ``` + +use crate::mir::join_ir::lowering::loop_to_join::LoopToJoinLowerer; +use crate::mir::join_ir::JoinInst; +use crate::mir::loop_form::LoopForm; + +/// Lowering for Pattern 3: Loop with If-Else PHI +/// +/// # Transformation (Pseudocode from design.md) +/// +/// ```text +/// fn loop_step(i, sum): +/// exit_cond = !(i <= 5) +/// Jump(k_exit, [sum], cond=exit_cond) +/// sum_new = Select(cond=(i%2==1), then=sum+i, else=sum+0) +/// i_next = i + 1 +/// Call(loop_step, [i_next, sum_new]) +/// ``` +/// +/// # Steps (from design.md § Pattern 3 § Step-by-Step Transformation) +/// +/// 1. **Extract Loop Variables** (multiple carriers: i + sum) +/// 2. **Create loop_step Function** (params: i, sum, k_exit) +/// 3. **Create k_exit with Exit PHI** (receives sum exit value) +/// 4. **Generate Exit Condition Check** (same as Pattern 1) +/// 5. **Translate If-Else to Select** +/// - Use existing If lowering (Phase 33: Select/IfMerge) +/// - Generate: `sum_new = Select(cond, then_val, else_val)` +/// 6. **Translate Loop Body** (remaining instructions) +/// 7. **Generate Tail Recursion** (with multiple carriers: i_next, sum_new) +/// +/// # Key Difference from Pattern 1 +/// +/// - **Multiple Carrier Variables**: Loop updates i + sum +/// - **In-Loop If Lowering**: Reuses existing Select/IfMerge lowering +/// - **PHI in Loop Body**: If-else assigns to same variable (becomes Select) +/// +/// # Arguments +/// +/// * `loop_form` - The loop structure to lower (must have if-else in body) +/// * `lowerer` - The LoopToJoinLowerer builder +/// +/// # Returns +/// +/// * `Some(JoinInst)` - Lowering succeeded, returns generated JoinIR instruction +/// * `None` - Lowering failed (pattern not matched or unsupported) +/// +/// # Errors +/// +/// Returns `None` if: +/// - Loop has breaks or continues +/// - If-else does not assign to same variable +/// - If context cannot be resolved +/// +/// # Reference +/// +/// See design.md § Pattern 3 for complete transformation details and pseudocode. +/// +/// # Example Usage +/// +/// ```rust,ignore +/// use crate::mir::loop_pattern_detection::is_loop_with_conditional_phi_pattern; +/// +/// if is_loop_with_conditional_phi_pattern(&loop_form) { +/// lower_loop_with_conditional_phi_to_joinir(&loop_form, &mut lowerer)?; +/// } +/// ``` +pub fn lower_loop_with_conditional_phi_to_joinir( + _loop_form: &LoopForm, + _lowerer: &mut LoopToJoinLowerer, +) -> Option { + // Phase 188-Impl-3: Delegate to minimal lowerer + // TODO: Extract LoopScopeShape from loop_form for generic implementation + use crate::mir::join_ir::lowering::loop_scope_shape::LoopScopeShape; + use crate::mir::join_ir::lowering::loop_with_if_phi_minimal::lower_loop_with_if_phi_pattern; + use crate::mir::BasicBlockId; + use std::collections::{BTreeMap, BTreeSet}; + + // For now, use a placeholder LoopScopeShape + // TODO: Build actual LoopScopeShape from loop_form + let placeholder_scope = LoopScopeShape { + header: BasicBlockId(0), + body: BasicBlockId(0), + latch: BasicBlockId(0), + exit: BasicBlockId(0), + pinned: BTreeSet::new(), + carriers: BTreeSet::new(), + body_locals: BTreeSet::new(), + exit_live: BTreeSet::new(), + progress_carrier: None, + variable_definitions: BTreeMap::new(), + }; + + // Generate JoinIR module + let _join_module = lower_loop_with_if_phi_pattern(placeholder_scope)?; + + // Phase 188-Impl-3: Pattern 3 is now integrated via the router + // This function delegates to loop_with_if_phi_minimal which generates JoinModule + // + // TODO: Either: + // 1. Remove this function and rely only on router integration, OR + // 2. Implement JoinModule → JoinInst conversion here (future phase) + + eprintln!("[loop_patterns] Pattern 3: Lowering delegated to loop_with_if_phi_minimal"); + + // Temporary: Return None to trigger fallback + // Pattern 3 currently works via router which calls minimal lowerer directly + None +} diff --git a/src/mir/join_ir/lowering/mod.rs b/src/mir/join_ir/lowering/mod.rs index c509f27c..1d0f5660 100644 --- a/src/mir/join_ir/lowering/mod.rs +++ b/src/mir/join_ir/lowering/mod.rs @@ -1,6 +1,7 @@ //! JoinIR Lowering Functions //! //! Phase 27.9: Modular separation of MIR → JoinIR lowering implementations. +//! Phase 33-12: Router-based If/Loop lowering organization. //! //! このモジュールは各種 MIR 関数を JoinIR に変換する lowering 関数を提供します。 //! @@ -15,6 +16,8 @@ //! - `if_select.rs`: Phase 33 If/Else → Select lowering //! - `if_dry_runner.rs`: Phase 33-10 If lowering dry-run スキャナー(箱化版) //! - `bool_expr_lowerer.rs`: Phase 168 Boolean expression lowering (AST → SSA) +//! - `if_lowering_router.rs`: Phase 33-12 If-expression routing (Select/IfMerge dispatcher) +//! - `loop_pattern_router.rs`: Phase 33-12 Loop pattern routing (Pattern 1-4 dispatcher) pub mod bool_expr_lowerer; // Phase 168: Boolean expression lowering for complex conditions pub mod carrier_info; // Phase 196: Carrier metadata for loop lowering @@ -28,12 +31,14 @@ pub mod generic_case_a; // Phase 192: Modularized Case A lowering pub mod generic_type_resolver; // Phase 66: P3-C ジェネリック型推論箱 pub mod method_return_hint; // Phase 83: P3-D 既知メソッド戻り値型推論箱 pub mod if_dry_runner; // Phase 33-10.0 +pub mod if_lowering_router; // Phase 33-12: If-expression routing pub mod if_merge; // Phase 33-7 pub mod if_phi_context; // Phase 61-1 pub mod if_phi_spec; // Phase 61-2 pub mod if_select; // Phase 33 pub mod inline_boundary; // Phase 188-Impl-3: JoinIR→Host boundary pub mod loop_form_intake; +pub mod loop_pattern_router; // Phase 33-12: Loop pattern routing pub mod loop_patterns; // Phase 188: Pattern-based loop lowering (3 patterns) pub mod loop_scope_shape; pub mod loop_to_join; @@ -64,10 +69,9 @@ pub use stage1_using_resolver::lower_stage1_usingresolver_to_joinir; pub use stageb_body::lower_stageb_body_to_joinir; pub use stageb_funcscanner::lower_stageb_funcscanner_to_joinir; -// Phase 33: If/Else → Select lowering entry point -use crate::mir::join_ir::JoinInst; -use crate::mir::loop_form::LoopForm; // Phase 188: Loop pattern lowering -use crate::mir::{BasicBlockId, MirFunction}; +// Phase 33-12: Re-export router functions (backward compatibility) +pub use if_lowering_router::try_lower_if_to_joinir; +pub use loop_pattern_router::try_lower_loop_pattern_to_joinir; /// Phase 33-9.1: Loop lowering対象関数の判定 /// @@ -179,300 +183,6 @@ pub fn is_joinir_if_toplevel_target(name: &str) -> bool { false } -/// Phase 33-7: Try to lower if/else to JoinIR Select/IfMerge instruction -/// -/// Scope: -/// - Only applies to whitelisted functions: -/// - IfSelectTest.* (Phase 33-2/33-3) -/// - IfMergeTest.* (Phase 33-7) -/// - JsonShapeToMap._read_value_from_pair/1 (Phase 33-4 Stage-1) -/// - Stage1JsonScannerBox.value_start_after_key_pos/2 (Phase 33-4 Stage-B) -/// - Requires JoinIR If-select toggle (HAKO_JOINIR_IF_SELECT / joinir_if_select_enabled) -/// - Falls back to traditional if_phi on pattern mismatch -/// -/// Pattern selection: -/// - 1 variable → Select -/// - 2+ variables → IfMerge -/// -/// Phase 61-1: If-in-loop support -/// - `context` parameter: If-in-loop context (carrier_names for loop variables) -/// - None = Pure If, Some(_) = If-in-loop -/// -/// Returns Some(JoinInst::Select) or Some(JoinInst::IfMerge) if pattern matched, None otherwise. -pub fn try_lower_if_to_joinir( - func: &MirFunction, - block_id: BasicBlockId, - debug: bool, - context: Option<&if_phi_context::IfPhiContext>, // Phase 61-1: If-in-loop context -) -> Option { - // 1. dev/Core トグルチェック - // - // - Core: joinir_core_enabled() / joinir_if_select_enabled() - // - Dev: joinir_dev_enabled()(詳細ログ等) - // - // 実際の挙動切り替えは joinir_if_select_enabled() に集約し、 - // Core/Dev ポリシーは config::env 側で判定する。 - if !crate::config::env::joinir_if_select_enabled() { - return None; - } - let core_on = crate::config::env::joinir_core_enabled(); - // Phase 185: strict check moved to caller (if_form.rs) - // let strict_on = crate::config::env::joinir_strict_enabled(); - - // Phase 33-9.1: Loop専任関数の除外(Loop/If責務分離) - // Loop lowering対象関数はIf loweringの対象外にすることで、 - // 1関数につき1 loweringの原則を保証します - if is_loop_lowered_function(&func.signature.name) { - return None; - } - - // Phase 33-8: デバッグログレベル取得(0-3) - let debug_level = crate::config::env::joinir_debug_level(); - let _debug = debug || debug_level >= 1; - - // 2. Phase 33-8: 関数名ガード拡張(テスト + Stage-1 rollout + 明示承認) - let is_allowed = - // Test functions (always enabled) - func.signature.name.starts_with("IfSelectTest.") || - func.signature.name.starts_with("IfSelectLocalTest.") || // Phase 33-10 test - func.signature.name.starts_with("IfMergeTest.") || - func.signature.name.starts_with("IfToplevelTest.") || // Phase 61-4: loop-outside if test - func.signature.name.starts_with("Stage1JsonScannerTestBox.") || // Phase 33-5 test - - // Stage-1 rollout (env-controlled) - (crate::config::env::joinir_stage1_enabled() && - func.signature.name.starts_with("Stage1")) || - - // Explicit approvals (Phase 33-4で検証済み, always on) - matches!(func.signature.name.as_str(), - "JsonShapeToMap._read_value_from_pair/1" | - "Stage1JsonScannerBox.value_start_after_key_pos/2" - ); - - // Phase 80: Core ON のときは許可リストを「JoinIRをまず試す」対象とみなす。 - // Core OFF のときは従来どおり whitelist + env に頼る。 - if !is_allowed || !core_on { - // Core OFF かつ許可外なら従来のガードでスキップ - if !is_allowed { - if debug_level >= 2 { - eprintln!( - "[try_lower_if_to_joinir] skipping non-allowed function: {}", - func.signature.name - ); - } - return None; - } - } - // Phase 185: strict_allowed removed (strict check moved to caller: if_form.rs) - - if debug_level >= 1 { - eprintln!( - "[try_lower_if_to_joinir] trying to lower {}", - func.signature.name - ); - } - - // 3. Phase 33-7: IfMerge を優先的に試行(複数変数パターン) - // IfMerge が成功すればそれを返す、失敗したら Select を試行 - // Phase 61-1: context がある場合は with_context() を使用 - let if_merge_lowerer = if let Some(ctx) = context { - if_merge::IfMergeLowerer::with_context(debug_level, ctx.clone()) - } else { - if_merge::IfMergeLowerer::new(debug_level) - }; - - if if_merge_lowerer.can_lower_to_if_merge(func, block_id) { - if let Some(result) = if_merge_lowerer.lower_if_to_if_merge(func, block_id) { - if debug_level >= 1 { - eprintln!( - "[try_lower_if_to_joinir] ✅ IfMerge lowering used for {}", - func.signature.name - ); - } - return Some(result); - } - } - - // 4. IfMerge が失敗したら Select を試行(単一変数パターン) - // Phase 61-1: context がある場合は with_context() を使用 - let if_select_lowerer = if let Some(ctx) = context { - if_select::IfSelectLowerer::with_context(debug_level, ctx.clone()) - } else { - if_select::IfSelectLowerer::new(debug_level) - }; - - // Phase 185: Remove strict checks from lowerer (thin Result-returning box) - // Strict mode panic should happen at caller level (if_form.rs), not here - if !if_select_lowerer.can_lower_to_select(func, block_id) { - if debug_level >= 1 { - eprintln!( - "[try_lower_if_to_joinir] pattern not matched for {}", - func.signature.name - ); - } - return None; - } - - let result = if_select_lowerer.lower_if_to_select(func, block_id); - - if result.is_some() && debug_level >= 1 { - eprintln!( - "[try_lower_if_to_joinir] ✅ Select lowering used for {}", - func.signature.name - ); - } - - result -} - -// ============================================================================ -// Phase 188: Loop Pattern-Based Lowering Router -// ============================================================================ - -/// Phase 188: Try to lower loop to JoinIR using pattern-based approach -/// -/// This function routes loop lowering to specific pattern handlers based on -/// loop structure characteristics. It tries patterns in order of complexity: -/// -/// 1. **Pattern 1: Simple While** (foundational, easiest) -/// 2. **Pattern 2: Break** (medium complexity) -/// 3. **Pattern 3: If-Else PHI** (leverages existing If lowering) -/// -/// # Arguments -/// -/// * `loop_form` - The loop structure to lower -/// * `lowerer` - The LoopToJoinLowerer builder (provides ValueId allocation, etc.) -/// -/// # Returns -/// -/// * `Some(JoinInst)` - Successfully lowered to JoinIR -/// * `None` - No pattern matched (fallback to existing lowering) -/// -/// # Pattern Selection Strategy -/// -/// Patterns are tried sequentially. First matching pattern wins. -/// If no pattern matches, returns `Ok(None)` to trigger fallback. -/// -/// ## Pattern 1: Simple While Loop -/// - **Condition**: Empty break/continue targets, single latch -/// - **Handler**: `loop_patterns::lower_simple_while_to_joinir()` -/// - **Priority**: First (most common, simplest) -/// -/// ## Pattern 2: Loop with Conditional Break -/// - **Condition**: Non-empty break_targets, exactly 1 break -/// - **Handler**: `loop_patterns::lower_loop_with_break_to_joinir()` -/// - **Priority**: Second (common, medium complexity) -/// -/// ## Pattern 3: Loop with If-Else PHI -/// - **Condition**: Empty break/continue, if-else in body -/// - **Handler**: `loop_patterns::lower_loop_with_conditional_phi_to_joinir()` -/// - **Priority**: Third (reuses If lowering infrastructure) -/// -/// # Integration Point -/// -/// This function should be called from loop lowering entry points: -/// - `loop_to_join.rs::LoopToJoinLowerer::lower_loop()` -/// - `loop_form_intake.rs::handle_loop_form()` -/// -/// # Example Usage -/// -/// ```rust,ignore -/// use crate::mir::join_ir::lowering::try_lower_loop_pattern_to_joinir; -/// -/// // In loop lowering entry point: -/// if let Some(joinir_inst) = try_lower_loop_pattern_to_joinir(&loop_form, &mut lowerer) { -/// // Pattern matched, use JoinIR -/// return Some(joinir_inst); -/// } -/// // No pattern matched, use existing lowering -/// existing_loop_lowering(&loop_form, &mut lowerer) -/// ``` -/// -/// # Reference -/// -/// See design.md for complete pattern specifications and transformation rules: -/// `docs/private/roadmap2/phases/phase-188-joinir-loop-pattern-expansion/design.md` -/// -/// # TODO (Phase 188 Task 188-4 Implementation) -/// -/// This function is a skeleton. Implementation steps: -/// -/// 1. **Implement Pattern Detection** (Step 1: 6-8h) -/// - Complete `loop_pattern_detection::is_simple_while_pattern()` -/// - Test with `apps/tests/loop_min_while.hako` -/// -/// 2. **Implement Pattern 1 Lowering** (Step 1: 6-8h) -/// - Complete `loop_patterns::lower_simple_while_to_joinir()` -/// - Verify no [joinir/freeze] error -/// -/// 3. **Implement Pattern 2** (Step 2: 6-10h) -/// - Complete `loop_pattern_detection::is_loop_with_break_pattern()` -/// - Complete `loop_patterns::lower_loop_with_break_to_joinir()` -/// - Test with `apps/tests/joinir_min_loop.hako` -/// -/// 4. **Implement Pattern 3** (Step 3: 6-10h) -/// - Complete `loop_pattern_detection::is_loop_with_conditional_phi_pattern()` -/// - Complete `loop_patterns::lower_loop_with_conditional_phi_to_joinir()` -/// - Test with `apps/tests/loop_if_phi.hako` -/// -/// 5. **Integration Testing** (Step 4: 2-4h) -/// - Run all 3 tests with JoinIR-only -/// - Verify no regressions -/// - Document results -/// -/// **Total Estimated Effort**: 18-28 hours -pub fn try_lower_loop_pattern_to_joinir( - loop_form: &LoopForm, - lowerer: &mut LoopToJoinLowerer, -) -> Option { - // Phase 194: Structure-based pattern classification - // Tries patterns based on CFG structure, not function names - - use crate::mir::loop_pattern_detection::{classify, extract_features, LoopPatternKind}; - - // Step 1: Extract features from LoopForm (no LoopScope needed for now) - let features = extract_features(loop_form, None); - - // Step 2: Classify pattern based on structure - let pattern = classify(&features); - - // Step 3: Route to appropriate lowerer based on pattern - match pattern { - LoopPatternKind::Pattern4Continue => { - if let Some(inst) = loop_patterns::lower_loop_with_continue_to_joinir(loop_form, lowerer) { - eprintln!("[try_lower_loop_pattern] ✅ Pattern 4 (Continue) matched"); - return Some(inst); - } - } - LoopPatternKind::Pattern3IfPhi => { - if let Some(inst) = loop_patterns::lower_loop_with_conditional_phi_to_joinir(loop_form, lowerer) { - eprintln!("[try_lower_loop_pattern] ✅ Pattern 3 (If-Else PHI) matched"); - return Some(inst); - } - } - LoopPatternKind::Pattern2Break => { - if let Some(inst) = loop_patterns::lower_loop_with_break_to_joinir(loop_form, lowerer) { - eprintln!("[try_lower_loop_pattern] ✅ Pattern 2 (Break) matched"); - return Some(inst); - } - } - LoopPatternKind::Pattern1SimpleWhile => { - if let Some(inst) = loop_patterns::lower_simple_while_to_joinir(loop_form, lowerer) { - eprintln!("[try_lower_loop_pattern] ✅ Pattern 1 (Simple While) matched"); - return Some(inst); - } - } - LoopPatternKind::Unknown => { - eprintln!("[try_lower_loop_pattern] ❌ Unknown pattern, fallback to existing lowering"); - } - } - - // No Pattern Matched (fallback to existing lowering) - // =================================================== - eprintln!("[try_lower_loop_pattern] ❌ Pattern lowering failed, fallback to existing lowering"); - None -} - #[cfg(test)] mod tests { use super::*;