diff --git a/src/mir/builder/control_flow/joinir/mod.rs b/src/mir/builder/control_flow/joinir/mod.rs new file mode 100644 index 00000000..7f64b44c --- /dev/null +++ b/src/mir/builder/control_flow/joinir/mod.rs @@ -0,0 +1,7 @@ +//! JoinIR integration for control flow +//! +//! This module contains JoinIR-related control flow logic: +//! - Pattern lowerers (patterns/) +//! - Routing logic (future Phase 3) + +pub(in crate::mir::builder) mod patterns; diff --git a/src/mir/builder/control_flow/joinir/patterns/mod.rs b/src/mir/builder/control_flow/joinir/patterns/mod.rs new file mode 100644 index 00000000..c5b5bb5c --- /dev/null +++ b/src/mir/builder/control_flow/joinir/patterns/mod.rs @@ -0,0 +1,10 @@ +//! Pattern lowerers for different loop constructs +//! +//! Phase 2: Extracted from control_flow.rs +//! - Pattern 1: Simple While Loop (pattern1_minimal.rs) +//! - Pattern 2: Loop with Conditional Break (pattern2_with_break.rs) +//! - Pattern 3: Loop with If-Else PHI (pattern3_with_if_phi.rs) + +pub(in crate::mir::builder) mod pattern1_minimal; +pub(in crate::mir::builder) mod pattern2_with_break; +pub(in crate::mir::builder) mod pattern3_with_if_phi; diff --git a/src/mir/builder/control_flow/joinir/patterns/pattern1_minimal.rs b/src/mir/builder/control_flow/joinir/patterns/pattern1_minimal.rs new file mode 100644 index 00000000..7c1d994b --- /dev/null +++ b/src/mir/builder/control_flow/joinir/patterns/pattern1_minimal.rs @@ -0,0 +1,156 @@ +//! Pattern 1: Simple While Loop minimal lowerer + +use crate::ast::ASTNode; +use crate::mir::builder::MirBuilder; +use crate::mir::ValueId; + +impl MirBuilder { + /// Phase 188-Impl-1-F: Pattern 1 (Simple While Loop) minimal lowerer + /// + /// This bypasses the LoopFrontendBinding JSON path and directly calls + /// the Pattern 1 minimal lowerer for apps/tests/loop_min_while.hako + /// + /// # Phase 188-Impl-2: Host Variable Integration + /// + /// Extracts the loop variable from the host function (e.g., `i` from `i < 3`) + /// and passes it to the Pattern 1 lowerer along with a ValueId allocator. + /// + /// # Pipeline + /// 1. Extract loop variable name from condition + /// 2. Look up ValueId in host variable_map + /// 3. Create Pattern1Context with host variable + allocator + /// 4. Call simple_while_minimal::lower_simple_while_minimal() → JoinModule + /// 5. convert_join_module_to_mir_with_meta() → MirModule + /// 6. Merge MIR blocks into current_function + pub(in crate::mir::builder) fn cf_loop_pattern1_minimal( + &mut self, + condition: &ASTNode, + _body: &[ASTNode], + _func_name: &str, + debug: bool, + ) -> Result, String> { + use crate::mir::join_ir::lowering::simple_while_minimal::{ + lower_simple_while_minimal, Pattern1Context, + }; + use crate::mir::join_ir_vm_bridge::convert_join_module_to_mir_with_meta; + use crate::mir::BasicBlockId; + use std::collections::{BTreeMap, BTreeSet}; + + if debug { + eprintln!("[cf_loop/joinir/pattern1] Calling Pattern 1 minimal lowerer"); + } + + // Phase 188-Impl-2: Extract loop variable from condition + // For `i < 3`, extract `i` and look up its ValueId in variable_map + let loop_var_name = self.extract_loop_variable_from_condition(condition)?; + let loop_var_id = self + .variable_map + .get(&loop_var_name) + .copied() + .ok_or_else(|| { + format!( + "[cf_loop/pattern1] Loop variable '{}' not found in variable_map", + loop_var_name + ) + })?; + + if debug { + eprintln!( + "[cf_loop/joinir/pattern1] Loop variable '{}' → {:?}", + loop_var_name, loop_var_id + ); + } + + // Create a minimal LoopScopeShape (Phase 188: hardcoded for loop_min_while.hako) + // Pattern 1 lowerer ignores the scope anyway, so this is just a placeholder + use crate::mir::join_ir::lowering::loop_scope_shape::LoopScopeShape; + let 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(), + }; + + // Phase 188-Impl-2: Create Pattern1Context with host variable + allocator + // Clone value_gen to move into closure + let mut value_gen_clone = self.value_gen.clone(); + let ctx = Pattern1Context { + loop_var: loop_var_id, + value_allocator: Box::new(move || value_gen_clone.next()), + }; + + // Call Pattern 1 lowerer with host context + let join_module = match lower_simple_while_minimal(scope, Some(ctx)) { + Some(module) => module, + None => { + if debug { + eprintln!("[cf_loop/joinir/pattern1] Pattern 1 lowerer returned None"); + } + return Ok(None); + } + }; + + if debug { + eprintln!( + "[cf_loop/joinir/pattern1] JoinModule generated with {} functions", + join_module.functions.len() + ); + } + + // Convert JoinModule to MirModule + // Phase 188: Pass empty meta map since Pattern 1 lowerer doesn't use metadata + use crate::mir::join_ir::frontend::JoinFuncMetaMap; + let empty_meta: JoinFuncMetaMap = BTreeMap::new(); + + let mir_module = convert_join_module_to_mir_with_meta(&join_module, &empty_meta) + .map_err(|e| format!("[cf_loop/joinir/pattern1] MIR conversion failed: {:?}", e))?; + + if debug { + eprintln!( + "[cf_loop/joinir/pattern1] MirModule generated with {} functions", + mir_module.functions.len() + ); + } + + // Merge JoinIR blocks into current function + // Phase 188-Impl-3: Create and pass JoinInlineBoundary for Pattern 1 + let boundary = crate::mir::join_ir::lowering::inline_boundary::JoinInlineBoundary::new_inputs_only( + vec![ValueId(0)], // JoinIR's main() parameter (loop variable) + vec![loop_var_id], // Host's loop variable + ); + // Phase 189: Discard exit PHI result (Pattern 1 returns void) + let _ = self.merge_joinir_mir_blocks(&mir_module, Some(&boundary), debug)?; + + // Phase 188-Impl-4-FIX: Return Void instead of trying to emit Const + // + // PROBLEM: Emitting instructions after merge_joinir_mir_blocks is fragile because: + // 1. merge creates exit block and switches to it + // 2. We try to add Const to exit block + // 3. But subsequent code (return statement) might overwrite the block + // + // SOLUTION: Loops don't produce values - they return Void. + // The subsequent "return 0" statement will emit its own Const + Return. + // + // This is cleaner because: + // - Loop lowering doesn't need to know about the return value + // - The return statement handles its own code generation + // - No risk of instructions being lost due to block management issues + + let void_val = crate::mir::builder::emission::constant::emit_void(self); + + if debug { + eprintln!( + "[cf_loop/joinir/pattern1] Loop complete, returning Void {:?}", + void_val + ); + } + + Ok(Some(void_val)) + } +} diff --git a/src/mir/builder/control_flow/joinir/patterns/pattern2_with_break.rs b/src/mir/builder/control_flow/joinir/patterns/pattern2_with_break.rs new file mode 100644 index 00000000..8b610c13 --- /dev/null +++ b/src/mir/builder/control_flow/joinir/patterns/pattern2_with_break.rs @@ -0,0 +1,127 @@ +//! Pattern 2: Loop with Conditional Break minimal lowerer + +use crate::ast::ASTNode; +use crate::mir::builder::MirBuilder; +use crate::mir::ValueId; + +impl MirBuilder { + /// Phase 188-Impl-2: Pattern 2 (Loop with Conditional Break) minimal lowerer + /// + /// Similar to Pattern 1, but handles loops with break statements. + /// + /// # Steps + /// 1. Extract loop variable from condition + /// 2. Generate JoinIR using loop_with_break_minimal + /// 3. Convert JoinModule → MirModule + /// 4. Create JoinInlineBoundary for input mapping + /// 5. Merge MIR blocks into current_function + /// 6. Return Void (loop doesn't produce values) + pub(in crate::mir::builder) fn cf_loop_pattern2_with_break( + &mut self, + condition: &ASTNode, + _body: &[ASTNode], + _func_name: &str, + debug: bool, + ) -> Result, String> { + use crate::mir::join_ir::lowering::loop_with_break_minimal::lower_loop_with_break_minimal; + use crate::mir::join_ir_vm_bridge::convert_join_module_to_mir_with_meta; + use crate::mir::BasicBlockId; + use std::collections::{BTreeMap, BTreeSet}; + + if debug { + eprintln!("[cf_loop/joinir/pattern2] Calling Pattern 2 minimal lowerer"); + } + + // Phase 188-Impl-2: Extract loop variable from condition + // For `i < 3`, extract `i` and look up its ValueId in variable_map + let loop_var_name = self.extract_loop_variable_from_condition(condition)?; + let loop_var_id = self + .variable_map + .get(&loop_var_name) + .copied() + .ok_or_else(|| { + format!( + "[cf_loop/pattern2] Loop variable '{}' not found in variable_map", + loop_var_name + ) + })?; + + if debug { + eprintln!( + "[cf_loop/joinir/pattern2] Loop variable '{}' → {:?}", + loop_var_name, loop_var_id + ); + } + + // Create a minimal LoopScopeShape (Phase 188: hardcoded for joinir_min_loop.hako) + // Pattern 2 lowerer ignores the scope anyway, so this is just a placeholder + use crate::mir::join_ir::lowering::loop_scope_shape::LoopScopeShape; + let 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(), + }; + + // Call Pattern 2 lowerer + let join_module = match lower_loop_with_break_minimal(scope) { + Some(module) => module, + None => { + if debug { + eprintln!("[cf_loop/joinir/pattern2] Pattern 2 lowerer returned None"); + } + return Ok(None); + } + }; + + if debug { + eprintln!( + "[cf_loop/joinir/pattern2] JoinModule generated with {} functions", + join_module.functions.len() + ); + } + + // Convert JoinModule to MirModule + // Phase 188: Pass empty meta map since Pattern 2 lowerer doesn't use metadata + use crate::mir::join_ir::frontend::JoinFuncMetaMap; + let empty_meta: JoinFuncMetaMap = BTreeMap::new(); + + let mir_module = convert_join_module_to_mir_with_meta(&join_module, &empty_meta) + .map_err(|e| format!("[cf_loop/joinir/pattern2] MIR conversion failed: {:?}", e))?; + + if debug { + eprintln!( + "[cf_loop/joinir/pattern2] MirModule generated with {} functions", + mir_module.functions.len() + ); + } + + // Merge JoinIR blocks into current function + // Phase 188-Impl-2: Create and pass JoinInlineBoundary for Pattern 2 + let boundary = crate::mir::join_ir::lowering::inline_boundary::JoinInlineBoundary::new_inputs_only( + vec![ValueId(0)], // JoinIR's main() parameter (loop variable init) + vec![loop_var_id], // Host's loop variable + ); + // Phase 189: Discard exit PHI result (Pattern 2 returns void) + let _ = self.merge_joinir_mir_blocks(&mir_module, Some(&boundary), debug)?; + + // Phase 188-Impl-2: Return Void (loops don't produce values) + // The subsequent "return i" statement will emit its own Load + Return + let void_val = crate::mir::builder::emission::constant::emit_void(self); + + if debug { + eprintln!( + "[cf_loop/joinir/pattern2] Loop complete, returning Void {:?}", + void_val + ); + } + + Ok(Some(void_val)) + } +} diff --git a/src/mir/builder/control_flow/joinir/patterns/pattern3_with_if_phi.rs b/src/mir/builder/control_flow/joinir/patterns/pattern3_with_if_phi.rs new file mode 100644 index 00000000..ab49a63d --- /dev/null +++ b/src/mir/builder/control_flow/joinir/patterns/pattern3_with_if_phi.rs @@ -0,0 +1,149 @@ +//! Pattern 3: Loop with If-Else PHI minimal lowerer + +use crate::ast::ASTNode; +use crate::mir::builder::MirBuilder; +use crate::mir::ValueId; + +impl MirBuilder { + /// Phase 188-Impl-3: Pattern 3 (Loop with If-Else PHI) minimal lowerer + /// + /// Handles loops with if-else statements that assign to carrier variables. + /// + /// # Steps + /// 1. Extract loop variables (carriers: i + sum) + /// 2. Generate JoinIR using loop_with_if_phi_minimal + /// 3. Convert JoinModule → MirModule + /// 4. Create JoinInlineBoundary for input mapping + /// 5. Merge MIR blocks into current_function + /// 6. Return Void (loop doesn't produce values) + pub(in crate::mir::builder) fn cf_loop_pattern3_with_if_phi( + &mut self, + condition: &ASTNode, + _body: &[ASTNode], + _func_name: &str, + debug: bool, + ) -> Result, String> { + use crate::mir::join_ir::lowering::loop_with_if_phi_minimal::lower_loop_with_if_phi_pattern; + use crate::mir::join_ir_vm_bridge::convert_join_module_to_mir_with_meta; + use crate::mir::BasicBlockId; + use std::collections::{BTreeMap, BTreeSet}; + + if debug { + eprintln!("[cf_loop/joinir/pattern3] Calling Pattern 3 minimal lowerer"); + } + + // Phase 188-Impl-3: Extract loop variable from condition + // For `i <= 5`, extract `i` and look up its ValueId in variable_map + let loop_var_name = self.extract_loop_variable_from_condition(condition)?; + let loop_var_id = self + .variable_map + .get(&loop_var_name) + .copied() + .ok_or_else(|| { + format!( + "[cf_loop/pattern3] Loop variable '{}' not found in variable_map", + loop_var_name + ) + })?; + + // Phase 188-Impl-3: Also get the accumulator variable (sum) + // For Pattern 3, we need both i and sum + let sum_var_id = self + .variable_map + .get("sum") + .copied() + .ok_or_else(|| { + format!( + "[cf_loop/pattern3] Accumulator variable 'sum' not found in variable_map" + ) + })?; + + if debug { + eprintln!( + "[cf_loop/joinir/pattern3] Loop variables: '{}' → {:?}, 'sum' → {:?}", + loop_var_name, loop_var_id, sum_var_id + ); + } + + // Create a minimal LoopScopeShape (Phase 188: hardcoded for loop_if_phi.hako) + // Pattern 3 lowerer ignores the scope anyway, so this is just a placeholder + use crate::mir::join_ir::lowering::loop_scope_shape::LoopScopeShape; + let 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(), + }; + + // Call Pattern 3 lowerer + let join_module = match lower_loop_with_if_phi_pattern(scope) { + Some(module) => module, + None => { + if debug { + eprintln!("[cf_loop/joinir/pattern3] Pattern 3 lowerer returned None"); + } + return Ok(None); + } + }; + + if debug { + eprintln!( + "[cf_loop/joinir/pattern3] JoinModule generated with {} functions", + join_module.functions.len() + ); + } + + // Convert JoinModule to MirModule + // Phase 188: Pass empty meta map since Pattern 3 lowerer doesn't use metadata + use crate::mir::join_ir::frontend::JoinFuncMetaMap; + let empty_meta: JoinFuncMetaMap = BTreeMap::new(); + + let mir_module = convert_join_module_to_mir_with_meta(&join_module, &empty_meta) + .map_err(|e| format!("[cf_loop/joinir/pattern3] MIR conversion failed: {:?}", e))?; + + if debug { + eprintln!( + "[cf_loop/joinir/pattern3] MirModule generated with {} functions", + mir_module.functions.len() + ); + } + + // Merge JoinIR blocks into current function + // Phase 190: Use explicit LoopExitBinding for Pattern 3 + // Pattern 3 has TWO carriers: i and sum + self.trace_varmap("pattern3_before_merge"); + let boundary = crate::mir::join_ir::lowering::inline_boundary::JoinInlineBoundary::new_with_exit_bindings( + vec![ValueId(0), ValueId(1)], // JoinIR's main() parameters (i, sum init) + vec![loop_var_id, sum_var_id], // Host's loop variables + vec![ + crate::mir::join_ir::lowering::inline_boundary::LoopExitBinding { + carrier_name: "sum".to_string(), + join_exit_value: ValueId(18), // k_exit's parameter (sum_final) + host_slot: sum_var_id, // variable_map["sum"] + } + ], + ); + let _exit_phi_result = self.merge_joinir_mir_blocks(&mir_module, Some(&boundary), debug)?; + self.trace_varmap("pattern3_after_merge"); + + // Phase 189-Refine: variable_map の更新は merge_joinir_mir_blocks 内で + // JoinInlineBoundary.host_outputs を用いて行われる。 + // この関数では Void を返すだけでよい(戻り値は後続の `return sum` が扱う)。 + let void_val = crate::mir::builder::emission::constant::emit_void(self); + + if debug { + eprintln!( + "[cf_loop/joinir/pattern3] Loop complete, returning Void {:?}", + void_val + ); + } + + Ok(Some(void_val)) + } +} diff --git a/src/mir/builder/control_flow/mod.rs b/src/mir/builder/control_flow/mod.rs index a0a5851c..c0ad5b8c 100644 --- a/src/mir/builder/control_flow/mod.rs +++ b/src/mir/builder/control_flow/mod.rs @@ -1,9 +1,9 @@ //! Control-flow entrypoints (if/loop/try/throw) centralized here. //! //! This module is being modularized in phases: -//! - Phase 1: Debug utilities -//! - Phase 2: Pattern lowerers -//! - Phase 3: JoinIR routing +//! - Phase 1: Debug utilities (debug.rs) ✅ +//! - Phase 2: Pattern lowerers (joinir/patterns/) ✅ +//! - Phase 3: JoinIR routing (future) //! - Phase 4-19: Additional modularization (future) use super::{Effect, EffectMask, MirInstruction, ValueId}; @@ -12,6 +12,9 @@ use crate::ast::ASTNode; // Phase 1: Debug utilities pub(in crate::mir::builder) mod debug; +// Phase 2: JoinIR integration (patterns) +pub(in crate::mir::builder) mod joinir; + impl super::MirBuilder { /// Control-flow: block pub(super) fn cf_block(&mut self, statements: Vec) -> Result { @@ -412,416 +415,6 @@ impl super::MirBuilder { Ok(Some(void_val)) } - /// Phase 188-Impl-1-F: Pattern 1 (Simple While Loop) minimal lowerer - /// - /// This bypasses the LoopFrontendBinding JSON path and directly calls - /// the Pattern 1 minimal lowerer for apps/tests/loop_min_while.hako - /// - /// # Phase 188-Impl-2: Host Variable Integration - /// - /// Extracts the loop variable from the host function (e.g., `i` from `i < 3`) - /// and passes it to the Pattern 1 lowerer along with a ValueId allocator. - /// - /// # Pipeline - /// 1. Extract loop variable name from condition - /// 2. Look up ValueId in host variable_map - /// 3. Create Pattern1Context with host variable + allocator - /// 4. Call simple_while_minimal::lower_simple_while_minimal() → JoinModule - /// 5. convert_join_module_to_mir_with_meta() → MirModule - /// 6. Merge MIR blocks into current_function - fn cf_loop_pattern1_minimal( - &mut self, - condition: &ASTNode, - _body: &[ASTNode], - _func_name: &str, - debug: bool, - ) -> Result, String> { - use crate::mir::join_ir::lowering::simple_while_minimal::{ - lower_simple_while_minimal, Pattern1Context, - }; - use crate::mir::join_ir_vm_bridge::convert_join_module_to_mir_with_meta; - use crate::mir::BasicBlockId; - use std::collections::{BTreeMap, BTreeSet}; - - if debug { - eprintln!("[cf_loop/joinir/pattern1] Calling Pattern 1 minimal lowerer"); - } - - // Phase 188-Impl-2: Extract loop variable from condition - // For `i < 3`, extract `i` and look up its ValueId in variable_map - let loop_var_name = self.extract_loop_variable_from_condition(condition)?; - let loop_var_id = self - .variable_map - .get(&loop_var_name) - .copied() - .ok_or_else(|| { - format!( - "[cf_loop/pattern1] Loop variable '{}' not found in variable_map", - loop_var_name - ) - })?; - - if debug { - eprintln!( - "[cf_loop/joinir/pattern1] Loop variable '{}' → {:?}", - loop_var_name, loop_var_id - ); - } - - // Create a minimal LoopScopeShape (Phase 188: hardcoded for loop_min_while.hako) - // Pattern 1 lowerer ignores the scope anyway, so this is just a placeholder - use crate::mir::join_ir::lowering::loop_scope_shape::LoopScopeShape; - let 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(), - }; - - // Phase 188-Impl-2: Create Pattern1Context with host variable + allocator - // Clone value_gen to move into closure - let mut value_gen_clone = self.value_gen.clone(); - let ctx = Pattern1Context { - loop_var: loop_var_id, - value_allocator: Box::new(move || value_gen_clone.next()), - }; - - // Call Pattern 1 lowerer with host context - let join_module = match lower_simple_while_minimal(scope, Some(ctx)) { - Some(module) => module, - None => { - if debug { - eprintln!("[cf_loop/joinir/pattern1] Pattern 1 lowerer returned None"); - } - return Ok(None); - } - }; - - if debug { - eprintln!( - "[cf_loop/joinir/pattern1] JoinModule generated with {} functions", - join_module.functions.len() - ); - } - - // Convert JoinModule to MirModule - // Phase 188: Pass empty meta map since Pattern 1 lowerer doesn't use metadata - use crate::mir::join_ir::frontend::JoinFuncMetaMap; - let empty_meta: JoinFuncMetaMap = BTreeMap::new(); - - let mir_module = convert_join_module_to_mir_with_meta(&join_module, &empty_meta) - .map_err(|e| format!("[cf_loop/joinir/pattern1] MIR conversion failed: {:?}", e))?; - - if debug { - eprintln!( - "[cf_loop/joinir/pattern1] MirModule generated with {} functions", - mir_module.functions.len() - ); - } - - // Merge JoinIR blocks into current function - // Phase 188-Impl-3: Create and pass JoinInlineBoundary for Pattern 1 - let boundary = crate::mir::join_ir::lowering::inline_boundary::JoinInlineBoundary::new_inputs_only( - vec![ValueId(0)], // JoinIR's main() parameter (loop variable) - vec![loop_var_id], // Host's loop variable - ); - // Phase 189: Discard exit PHI result (Pattern 1 returns void) - let _ = self.merge_joinir_mir_blocks(&mir_module, Some(&boundary), debug)?; - - // Phase 188-Impl-4-FIX: Return Void instead of trying to emit Const - // - // PROBLEM: Emitting instructions after merge_joinir_mir_blocks is fragile because: - // 1. merge creates exit block and switches to it - // 2. We try to add Const to exit block - // 3. But subsequent code (return statement) might overwrite the block - // - // SOLUTION: Loops don't produce values - they return Void. - // The subsequent "return 0" statement will emit its own Const + Return. - // - // This is cleaner because: - // - Loop lowering doesn't need to know about the return value - // - The return statement handles its own code generation - // - No risk of instructions being lost due to block management issues - - let void_val = crate::mir::builder::emission::constant::emit_void(self); - - if debug { - eprintln!( - "[cf_loop/joinir/pattern1] Loop complete, returning Void {:?}", - void_val - ); - } - - Ok(Some(void_val)) - } - - /// Phase 188-Impl-2: Pattern 2 (Loop with Conditional Break) minimal lowerer - /// - /// Similar to Pattern 1, but handles loops with break statements. - /// - /// # Steps - /// 1. Extract loop variable from condition - /// 2. Generate JoinIR using loop_with_break_minimal - /// 3. Convert JoinModule → MirModule - /// 4. Create JoinInlineBoundary for input mapping - /// 5. Merge MIR blocks into current_function - /// 6. Return Void (loop doesn't produce values) - fn cf_loop_pattern2_with_break( - &mut self, - condition: &ASTNode, - _body: &[ASTNode], - _func_name: &str, - debug: bool, - ) -> Result, String> { - use crate::mir::join_ir::lowering::loop_with_break_minimal::lower_loop_with_break_minimal; - use crate::mir::join_ir_vm_bridge::convert_join_module_to_mir_with_meta; - use crate::mir::BasicBlockId; - use std::collections::{BTreeMap, BTreeSet}; - - if debug { - eprintln!("[cf_loop/joinir/pattern2] Calling Pattern 2 minimal lowerer"); - } - - // Phase 188-Impl-2: Extract loop variable from condition - // For `i < 3`, extract `i` and look up its ValueId in variable_map - let loop_var_name = self.extract_loop_variable_from_condition(condition)?; - let loop_var_id = self - .variable_map - .get(&loop_var_name) - .copied() - .ok_or_else(|| { - format!( - "[cf_loop/pattern2] Loop variable '{}' not found in variable_map", - loop_var_name - ) - })?; - - if debug { - eprintln!( - "[cf_loop/joinir/pattern2] Loop variable '{}' → {:?}", - loop_var_name, loop_var_id - ); - } - - // Create a minimal LoopScopeShape (Phase 188: hardcoded for joinir_min_loop.hako) - // Pattern 2 lowerer ignores the scope anyway, so this is just a placeholder - use crate::mir::join_ir::lowering::loop_scope_shape::LoopScopeShape; - let 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(), - }; - - // Call Pattern 2 lowerer - let join_module = match lower_loop_with_break_minimal(scope) { - Some(module) => module, - None => { - if debug { - eprintln!("[cf_loop/joinir/pattern2] Pattern 2 lowerer returned None"); - } - return Ok(None); - } - }; - - if debug { - eprintln!( - "[cf_loop/joinir/pattern2] JoinModule generated with {} functions", - join_module.functions.len() - ); - } - - // Convert JoinModule to MirModule - // Phase 188: Pass empty meta map since Pattern 2 lowerer doesn't use metadata - use crate::mir::join_ir::frontend::JoinFuncMetaMap; - let empty_meta: JoinFuncMetaMap = BTreeMap::new(); - - let mir_module = convert_join_module_to_mir_with_meta(&join_module, &empty_meta) - .map_err(|e| format!("[cf_loop/joinir/pattern2] MIR conversion failed: {:?}", e))?; - - if debug { - eprintln!( - "[cf_loop/joinir/pattern2] MirModule generated with {} functions", - mir_module.functions.len() - ); - } - - // Merge JoinIR blocks into current function - // Phase 188-Impl-2: Create and pass JoinInlineBoundary for Pattern 2 - let boundary = crate::mir::join_ir::lowering::inline_boundary::JoinInlineBoundary::new_inputs_only( - vec![ValueId(0)], // JoinIR's main() parameter (loop variable init) - vec![loop_var_id], // Host's loop variable - ); - // Phase 189: Discard exit PHI result (Pattern 2 returns void) - let _ = self.merge_joinir_mir_blocks(&mir_module, Some(&boundary), debug)?; - - // Phase 188-Impl-2: Return Void (loops don't produce values) - // The subsequent "return i" statement will emit its own Load + Return - let void_val = crate::mir::builder::emission::constant::emit_void(self); - - if debug { - eprintln!( - "[cf_loop/joinir/pattern2] Loop complete, returning Void {:?}", - void_val - ); - } - - Ok(Some(void_val)) - } - - /// Phase 188-Impl-3: Pattern 3 (Loop with If-Else PHI) minimal lowerer - /// - /// Handles loops with if-else statements that assign to carrier variables. - /// - /// # Steps - /// 1. Extract loop variables (carriers: i + sum) - /// 2. Generate JoinIR using loop_with_if_phi_minimal - /// 3. Convert JoinModule → MirModule - /// 4. Create JoinInlineBoundary for input mapping - /// 5. Merge MIR blocks into current_function - /// 6. Return Void (loop doesn't produce values) - fn cf_loop_pattern3_with_if_phi( - &mut self, - condition: &ASTNode, - _body: &[ASTNode], - _func_name: &str, - debug: bool, - ) -> Result, String> { - use crate::mir::join_ir::lowering::loop_with_if_phi_minimal::lower_loop_with_if_phi_pattern; - use crate::mir::join_ir_vm_bridge::convert_join_module_to_mir_with_meta; - use crate::mir::BasicBlockId; - use std::collections::{BTreeMap, BTreeSet}; - - if debug { - eprintln!("[cf_loop/joinir/pattern3] Calling Pattern 3 minimal lowerer"); - } - - // Phase 188-Impl-3: Extract loop variable from condition - // For `i <= 5`, extract `i` and look up its ValueId in variable_map - let loop_var_name = self.extract_loop_variable_from_condition(condition)?; - let loop_var_id = self - .variable_map - .get(&loop_var_name) - .copied() - .ok_or_else(|| { - format!( - "[cf_loop/pattern3] Loop variable '{}' not found in variable_map", - loop_var_name - ) - })?; - - // Phase 188-Impl-3: Also get the accumulator variable (sum) - // For Pattern 3, we need both i and sum - let sum_var_id = self - .variable_map - .get("sum") - .copied() - .ok_or_else(|| { - format!( - "[cf_loop/pattern3] Accumulator variable 'sum' not found in variable_map" - ) - })?; - - if debug { - eprintln!( - "[cf_loop/joinir/pattern3] Loop variables: '{}' → {:?}, 'sum' → {:?}", - loop_var_name, loop_var_id, sum_var_id - ); - } - - // Create a minimal LoopScopeShape (Phase 188: hardcoded for loop_if_phi.hako) - // Pattern 3 lowerer ignores the scope anyway, so this is just a placeholder - use crate::mir::join_ir::lowering::loop_scope_shape::LoopScopeShape; - let 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(), - }; - - // Call Pattern 3 lowerer - let join_module = match lower_loop_with_if_phi_pattern(scope) { - Some(module) => module, - None => { - if debug { - eprintln!("[cf_loop/joinir/pattern3] Pattern 3 lowerer returned None"); - } - return Ok(None); - } - }; - - if debug { - eprintln!( - "[cf_loop/joinir/pattern3] JoinModule generated with {} functions", - join_module.functions.len() - ); - } - - // Convert JoinModule to MirModule - // Phase 188: Pass empty meta map since Pattern 3 lowerer doesn't use metadata - use crate::mir::join_ir::frontend::JoinFuncMetaMap; - let empty_meta: JoinFuncMetaMap = BTreeMap::new(); - - let mir_module = convert_join_module_to_mir_with_meta(&join_module, &empty_meta) - .map_err(|e| format!("[cf_loop/joinir/pattern3] MIR conversion failed: {:?}", e))?; - - if debug { - eprintln!( - "[cf_loop/joinir/pattern3] MirModule generated with {} functions", - mir_module.functions.len() - ); - } - - // Merge JoinIR blocks into current function - // Phase 190: Use explicit LoopExitBinding for Pattern 3 - // Pattern 3 has TWO carriers: i and sum - self.trace_varmap("pattern3_before_merge"); - let boundary = crate::mir::join_ir::lowering::inline_boundary::JoinInlineBoundary::new_with_exit_bindings( - vec![ValueId(0), ValueId(1)], // JoinIR's main() parameters (i, sum init) - vec![loop_var_id, sum_var_id], // Host's loop variables - vec![ - crate::mir::join_ir::lowering::inline_boundary::LoopExitBinding { - carrier_name: "sum".to_string(), - join_exit_value: ValueId(18), // k_exit's parameter (sum_final) - host_slot: sum_var_id, // variable_map["sum"] - } - ], - ); - let exit_phi_result = self.merge_joinir_mir_blocks(&mir_module, Some(&boundary), debug)?; - self.trace_varmap("pattern3_after_merge"); - - // Phase 189-Refine: variable_map の更新は merge_joinir_mir_blocks 内で - // JoinInlineBoundary.host_outputs を用いて行われる。 - // この関数では Void を返すだけでよい(戻り値は後続の `return sum` が扱う)。 - let void_val = crate::mir::builder::emission::constant::emit_void(self); - - if debug { - eprintln!( - "[cf_loop/joinir/pattern3] Loop complete, returning Void {:?}", - void_val - ); - } - - Ok(Some(void_val)) - } /// Phase 49-3.2: Merge JoinIR-generated MIR blocks into current_function ///